AngularJS - how to add a conditional to bootstrap modal target? - javascript

So I have a modal that appears when a button is clicked - however I want the modal ONLY to appear when certain conditions are met (which are defined in my controller).
HTML CODE:
<button class="btn btn-primary-outline" type="button" data-uk-modal="{target:'#previewModal'
}" ng-click="previewOfferBefore()">Preview</button>
The above works (modal with the id 'previewModal' pops out on click). So my approach is to add the conditional in the controller and define the value of the "target" in there using Angular data binding.
ie:
<button class="btn btn-primary-outline" type="button" data-uk-modal="{target: {{ previewLink
}}}" ng-click="previewOfferBefore()">Preview </button>
Then the controller would have:
$scope.previewOfferBefore = function() {
if (/*some conditions here*/) {
$scope.previewLink = '#'; /*don't let a modal pop up */
}
else {
$scope.previewLink = '#previewModal' /*let the modal pop up */
}
}
One approach I tried as well is using ng-href instead of bootstrap's data-uk-modal and that also didn't work. I know my controller function is fine since when I place {{ previewLink }} inside a p html tag it prints out the right id I want. So the issue is how I'm binding the data inside the button class.

If you're okay with the button being disabled or greyed out, then one solution would be to use ng-disabled. Your controller would look something like this;
$scope.previewOfferBefore = function() {
if (/*some conditions here*/) {
$scope.canClick= true;
}
else {
$scope.canClick= false;
}
}
and your html would then become;
<button ng-disabled="canClick" class="btn btn-primary-outline" type="button" data-uk-modal="{target:'#previewModal'
}" ng-click="previewOfferBefore()">Preview</button>
Then your button will become unclickable if it hits the false case on the if statement.

You could simply have two buttons and use ng-if or ng-show to just show one of them depending on your expression. You can simply use angular inside.
<button ng-show="previewLink !== '#'" type="button" data-uk-modal="{target: '#previewLink'}" ng-click="previewOfferBefore()">
Preview
</button>
<button ng-show=""previewLink === '#'"" type="button" data-uk-modal="{target: '#'" ng-click="previewOfferBefore()">
Preview
</button>
Alternative:
I would try ng-attr to get your angular expression into the attribute like
ng-attr-uk-modal="{{'target:' + value}}"
and bind value to the target you need. I haven't tried this, might need some adjustments.

Related

Click and toggle between two classes on an array (no JQuery)

I need to make a site where I can add something to a shoppingcart. I do not need to store any data, so just changing a class to 'addedInCart' is enough. This is what I have so far, but it's not working yet. I know all the classnames I got are coming back in an array. I just dont know how to change them if the button is clicked. I tried a lot with the addEventListener and the toggle, but I just started coding, not everything is clear for me yet. I am not alloud to use Jquery, only HTML and Javascript.
This is what I have in Javascript:
var buyMe = document.getElementsByClassName("materials-icon");
function shoppingcart() {
for(let i = 0; i < buyMe.length; i++){
buyMe[i].classList.toggle("addedInCart");
buyMe[i].addEventListener("click", toggleClass, false)
}
}
This is what my button looks like:
<button class="material-icons" onclick="shoppingcart()"></button>
Thank you for your time!
Use event delegation to be able to use one handler. Use a data-attribute to verify the button as being a button for adding to cart. Something like:
document.addEventListener("click", handle);
function handle(evt) {
const origin = evt.target;
if (origin.dataset.cartToggle) {
// ^ if element has attribute data-cart-toggle...
origin.classList.toggle("addedInCart");
// ^ ... toggle the class
}
};
.addedInCart {
color: red;
}
.addedInCart:after {
content: " (in cart, click to remove)";
}
<button class="material-icons" data-cart-toggle="1">buy</button>
<button class="material-icons" data-cart-toggle="1">buy</button>
<button class="material-icons" data-cart-toggle="1">buy</button>

How do I change what a JS function does when called by different buttons?

I am learning Javascript and I'm trying to clean up my code. The code is pretty simple: it simply changes the color of some text by clicking some different buttons. When you click the red button the text turns red, the blue button the text turns blue, etc. Here is the code:
HTML:
<h1 id="title">Change my color!</h1>
<button id="btn" onclick="colorRed()">Red</button>
<button id="btn" onclick="colorGreen()">Green</button>
<button id="btn" onclick="colorBlue()">Blue</button>
<button id="btn" onclick="colorBlack()">Black</button>
Javascript:
var title = document.getElementById("title");
function colorRed() {
title.style.color = "red";
}
function colorGreen() {
title.style.color = "green";
}
function colorBlue() {
title.style.color = "blue";
}
function colorBlack() {
title.style.color = "black";
}
This code works. My question is how do I clean up my Javascript; in a case where I would've had 20 buttons, coding 20 different functions would obviously not be the way to go.
I did try the following for every single color, but that didn't work:
Javascript:
var title = document.getElementById("title");
var btn = document.getElementById("btn");
function changeColor() {
if(btn.innerHTML == "Red") {
title.style.color = "red";
} else if ...
}
I think it goes wrong when I try to identify which button has been clicked by seeing if their inner HTML is equal to a certain color, but I'm not sure how to fix that. Help would be much appreciated!
EDIT: My question isn't a duplicate of Change an element's background color when clicking a different element as the code I wrote works already, and I just want to learn how to clean it up.
Might be easiest to just make one changeColor function and pass it a color in the event:
var title = document.getElementById("title");
function changeColor(color) {
console.log(color);
title.style.color = color;
}
<h1 id="title">Change my color!</h1>
<button class="btn" onclick="changeColor('red')">Red</button>
<button class="btn" onclick="changeColor('green')">Green</button>
<button class="btn" onclick="changeColor('blue')">Blue</button>
<button class="btn" onclick="changeColor('black')">Black</button>
Side note: you really shouldn't repeat id's and should use class instead.
It is generally not advisable to use inline event handlers, use addEventListener instead. Rather than adding an event listener for each element, I would recommend adding a common parent element, attaching one event listener to that and inspect the event ("event delegation") to determine which color to apply:
var title = document.querySelector('#title');
document.querySelector('#button-container').addEventListener('click', function(event) {
var color = event.target.getAttribute('data-color')
title.style.color = color;
}, false)
<h1 id="title">Change my color!</h1>
<div id="button-container">
<button data-color="red">Red</button>
<button data-color="green">Green</button>
<button data-color="blue">Blue</button>
<button data-color="black">Black</button>
</div>
Don't use inline HTML event attributes, such as onclick. There are a variety of reasons why and if you are just starting with JavaScript, you don't want to pick up any bad habits. Instead, keep your JavaScript completely separate from your HTML and follow modern standards using the .addEventListener() JavaScript method for setting up event handlers.
Also, id values must be unique within a document (the whole point of them is to uniquely identify elements). To be able to group just the buttons that relate to this operation, you can give them all the same CSS class and then query on that class in JavaScript (shown below).
Next, you only need one function, but if your individual buttons were storing the color they should produce, that one function could extract it and use it without the need for any arguments to be passed to your function:
var title = document.getElementById("title");
// When you query your document for groups of matching elements (using methods
// like: getElementsByTagName or getElementsByClassName) you get back an object
// that is similar to an array, called a "node list". Although these "array-like"
// objects support some of the standard array object's features, they are not
// true arrays and don't implement many of the powerful array methods out there.
// But, we can convert the node list returned from .querySelectorAll into an array
// and then we can iterate the array with .forEach() looping method later.
var buttonArray = Array.prototype.slice.call(document.querySelectorAll(".colorBtn"));
// Loop through the button array (the function provided as an argument will be
// executed for each element in the array)
buttonArray.forEach(function(button){
// Set up click event handlers for each button
button.addEventListener("click", function(){
// Just set the color to the "data-color" attribute value on the element
title.style.color = button.dataset.color;
})
});
.colorBtn {
box-shadow:2px 2px 1px grey;
border-radius:4px;
width:100px;
display:inline-block;
margin:4px;
}
.colorBtn:hover, .colorBtn:active {
box-shadow:-2px -2px 1px #e0e0e0;
outline:none;
}
<h1 id="title">Change my color!</h1>
<!-- Putting related elements into the same class allows you to
not only style them identically, but also find them in
JavaScript more easily. -->
<button id="btn1" class="colorBtn" data-color="red">Red</button>
<button id="btn2" class="colorBtn" data-color="green">Green</button>
<button id="btn3" class="colorBtn" data-color="blue">Blue</button>
<button id="btn4" class="colorBtn" data-color="black">Black</button>
Another way to do this is the following:
function changeColor() {
title.style.color = btn.style.backgroundColor;
}
and set each buttons background to the appropriate color.
Rather than have the function figure out what color to change to, you could pass that color to the changeColor function. Your function would become:
function changeColor(color) {
title.style.color = color;
}
Then in your HTML, you would change the onclick properties to pass that in:
<button id="btn" onclick="changeColor('red')">Red</button>
...
Also, I wanted to mention that your issues before weren't just related to checking the innerHTML like you suggested in your post. One issue would be that you have multiple HTML elements with the same id. That isn't going to work well when using document.getElementById().
When you need a dynamic number of elements, we need an easy way to find them in the DOM. There are some helper methods out there, like getElementsByClassName() on the document object. The first thing I would do is drop the IDs on your buttons (which should be unique, by the way), in favor of a class name:
<button class="btn" onclick="colorRed()">Red</button>
<button class="btn" onclick="colorGreen()">Green</button>
<button class="btn" onclick="colorBlue()">Blue</button>
<button class="btn" onclick="colorBlack()">Black</button>
The second thing I would do is refactor this so that you can use good unobtrusive JavaScript practices (basically getting the JavaScript good out of the HTML markup and wiring it up all in a JavaScript code block). First, we need a way for the JavaScript to know which color you want to change the button text to. Let's introduce a custom HTML data- attribute in place of the hard-coded onclick handlers:
<button class="btn" data-color="red">Red</button>
<button class="btn" data-color="green">Green</button>
<button class="btn" data-color="blue">Blue</button>
<button class="btn" data-color="black">Black</button>
Now, we need a way to find these buttons so we can loop over them and apply an onclick handler. This can be done with the method I mentioned earlier:
var title = document.getElementById("title");
var buttons = document.getElementsByClassName("btn");
This will build you an array of the four buttons (or however many you have).
Then we need to loop over them and assign a click handler that retrieves the color from the data-color attribute and assigns it to the <h1> element's style.color property:
for (var btnIndex = 0; btnIndex < buttons.length; btnIndex++)
{
buttons[btnIndex].onclick = function() {
title.style.color = this.getAttribute('data-color');
}
}
And that's it! We eliminated all of the duplicate and practiced some better JavaScript techniques at the same time. Try the code out below:
var title = document.getElementById("title");
var buttons = document.getElementsByClassName("btn");
for (var btnIndex = 0; btnIndex < buttons.length; btnIndex++)
{
buttons[btnIndex].onclick = function() {
title.style.color = this.getAttribute('data-color');
}
}
<h1 id="title">Change my color!</h1>
<button class="btn" data-color="red">Red</button>
<button class="btn" data-color="green">Green</button>
<button class="btn" data-color="blue">Blue</button>
<button class="btn" data-color="black">Black</button>

How to change class name of two IDs at same time using js?

I have two IDs in same name ! if any one clicked among them , i need to change the class name of the both IDs. i know we should use ID for single use. Because of my situation(I have two classes for button ) so i have moved to ID.
Her is my code if i click one id that name only changes another one is remains same
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
js function
function reply(clicked_id)
{
document.getElementById(clicked_id).setAttribute('class', 'failed');
var el = document.getElementById(clicked_id);
if (el.firstChild.data == "Added")
{
el.firstChild.data = "Add";
}
}
if i use instead of 'class' to id while renaming class which one will be renamed success class or 'class name 1' ?
You can't. Getelementbyid will only return one element. Probably the first one.
Pure JS Is Second Example
My JS Fiddle Example: http://jsfiddle.net/eunzs7rz/
This example will use the class attribute only to perform the switching that you need, its a extremely basic example as do not want to go beyond what is needed... Also i forgot to remove the id's in the JS Fiddle Example.. so just ignore them
THE CSS:
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
THE HTML:
<button class="success"> Added </button>
<button class="success"> Added </button>
THE JAVSCRIPT:
$(function() {
$(".success").click(function(){
Reply(this);
});
});
function Reply(oElm) {
$(oElm).attr('class', 'failed');
}
EDIT - PURE JAVASCRIPT VERSION
Sorry, did not think to check the post tags if this was pure JS. But here you go anyway ;)
<style>
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
</style>
<button class="success" onclick="Reply(this)"> Added </button>
<button class="success" onclick="Reply(this)"> Added </button>
<script>
function Reply(oElm) {
oElm.className = 'failed';
}
</script>
THE MAIN THING HERE
Once you have the element either by using 'this' or by using 'getElementBy', you can then simply use ".className" to adjust the class attribute of the selected element.
As already explained by others, id is for single use and is quicker than using class or type. So even if you have a group, if only one is ever used.. use an id.
Then you use the object/reference of 'this' from an event on an element, in this case the onclick... that will send that variable to the function / code called.
So using 'this' is a preferred option as it will always reference the element that it is used/called from.
pass elemenet, not it's Id
<button class="success" id="1" onClick="reply(this)"> Added </button>
<button class="success" id="1" onClick="reply(this)"> Added </button>
function reply(elem)
{
$(elem).setAttribute('class', 'failed');
if (elem.firstChild.data == "Added")
{
elem.firstChild.data = "Add";
}
}
the ID attribute must be unique or else it will get the last defined element with that ID.
See this for reference.
Use a class instead of an id. ids are supposed to be unique in a dom tree.
html:
<button class="success" onClick="reply()"> Added </button>
<button class="success" onClick="reply()"> Added </button>
js:
var ary_success = document.querySelectorAll(".success"); // once and forever. If the set of elements changes, move into function `reply`
function reply () {
var elem;
var s_myclasses;
for (var i=0; i < ary_success.length; i++) {
elem = ary_success[i];
s_myclasses = elem.getAttribute('class');
s_myclasses = s_myclasses.replace ( /(success|failed)/g, '' );
s_myclasses = s_myclasses + ' failed';
elem.setAttribute('class', s_myclasses );
if ( elem.firstChild.data.indexOf("Added") !== -1) {
elem.firstChild.data = "Add";
}
}
}
Live Demo here.
Notes
Make sure that you set ary_successin the onload handler or in an appropriately placed script section - at the timeof execution the buttons must be present in the dom ! If in doubt, move it to the start of reply' body.
If you employ jquery, the code simplifies (well...) to:
$(document).ready( function () {
$(".success").on ( 'click', function ( eve ) {
$(".success").removeClass("success").addClass("failed");
$(".success *:first-child:contains('Added')").text(" Add ");
});
});
Updates
Notes, Live Demo
Iterator method changed, every not supported on test platform

innerHTML.replace not working in firefox but in IE

I want to rename the onclick method of a button. First my Button has following code:
<input id="my_button" class="update field-button" type="button" onclick="add( this )" value="ADD Something" title="ADD Item" name="my_button"></input>
Then I want something like this:
<input id="my_button" class="update field-button" type="button" onclick="remove( this )" value="ADD Something" title="ADD Item" name="my_button"></input>
I do the rename with this statement:
parentNode.innerHTML = parentNode.innerHTML.replace( /(onclick="?)[A-Za-z0-9\-]+(\([^)]*\)"?)/, "$1remove$2" );
parentNode is a var:
var parentNode = removeButton.parentNode;
In the Internet Explorer it works, but not in firefox
This is not the way to achieve your desired functionality, click handlers can be bound entirely with javascript.
Try the following:
document.getElementById('my_button').onclick = function() {
var toggle = false;
return function (e) {
toggle = !toggle;
toggle ? add(this) : remove(this);
};
}();
Though I would recommend the rich's answer and put that logic into the clickhandler, it might be interesting what your problem is.
Firefox does your replacement correctly and calls the buttons native remove-method as the click handler has the buttons's scope. So
onclick="remove( this )"
is the same as
onclick="document.getElementById('my_button').remove();"
and the button gets removed from the dom.

Can only click jQuery element once before it stops working

I've got the following code:
$("#another").click(function() {
$('#another').replaceWith('<a id="another" class="btn btn-primary btn-mini disabled"><i class="icon-refresh icon-white"></i> Loading...</a>');
$.get('another.php', { 'cycle' : i }, function(data) {
$('tbody').append(data);
$("#another").replaceWith('<a id="another" class="btn btn-primary btn-mini"><i class="icon-plus icon-white"></i> Load another cycle</a>');
});
i++;
});
When I click the element with the id of another, it loads once. After one click, it won't work again.
You're replacing the node with a node that doesn't have the event listener.
Basically before the click you have
[#another]
^
|
[clickListener]
You then build another button (<a id="another" class="btn btn-primary btn-mini disabled"><i class="icon-refresh icon-white"></i> Loading...</a>)
[#another] [#another](2)
^
|
[clickListener]
then we replace the first another with a second one in the layout:
[#another] [#another](2)
^
|
[clickListener]
oh wait, nothing changed in my model. That's because the click listener was linked to that first object ( that is no longer visible), whereas the visible one is still there.
So codewise, what does this mean? It simply means you'll need to attach the event listener back on there. Here's how I'd have done it
var onClick=function(){
$('#another').replaceWith('<a id="another" class="btn btn-primary btn-mini disabled"><i class="icon-refresh icon-white"></i> Loading...</a>')
.click(onClick); // <--- this is the important line!
$.get('another.php', { 'cycle' : i }, function(data) {
$('tbody').append(data);
$("#another").replaceWith('<a id="another" class="btn btn-primary btn-mini"><i class="icon-plus icon-white"></i> Load another cycle</a>');
});
i++;
}
$("#another").click(onClick);
If you replace the element with another, all listeners will be removed. To avoid this you either add the listener again to the new element
$('#another').bind('click', function() {
//do something
});
or move the code to a function and add a onclick attribute to your element.
onclick="my_function();"
in your current javascript it would be
$('#another').replaceWith('<a id="another" class="btn btn-primary btn-mini disabled" onclick="my_function();"><i class="icon-refresh icon-white"></i> Loading...</a>');
It's best to just keep the same button, with the same event handler. Just dynamically change the text and increment i. Try this:
// Execute in a closure to isolate all the local variables
// Optional, but I like doing this when counter variables are involved
(function() {
var button = $("#another");
var a = button.find("a");
var i = 1;
button.click(function() {
// Replace the inner html, not the entire element
a.html("<i class='icon-refresh icon-white'</i> Loading...");
$.get("another.php", {
cycle: i
}, function(data) {
$("tbody").append(data);
a.html("<i class='icon-plus icon-white'></i> Load another cycle");
i++;
});
});
})();
The benefit of this method is that there is less DOM manipulation, no inline JavaScript, and no global functions or variables. There really is no reason to destroy the button each time and recreate it if the outer markup is the same.

Categories

Resources