I got a question, what I have already solved, but it's just so annoying.
I have a js code, which is putting down some html code when a button is pushed with "append", and with that code I'm giving an id to an x button, and an id to the container element. I wanted to use these id-s to identify them with a click function, to remove the html code:
var num = 0;
$('.button').click(funcion(){
num++;
var code = '\
<div class="container" id="text' + num + '">\
<div id="x' + num + '">\
x\
</div>\
Some stuff\
</div>\
';
$('.puthere').append(code);
$('#x' + num).click(function(){
$('#text' + num).remove();
});
});
Now the annoying part is the click function on the x. What I would expect is, that this code would work somehow like this:
1st click on the "button" class element should give this code:
$('#x1').click(function(){
$('#text1').remove();
});
after 2nd click I should have this:
$('#x1').click(function(){
$('#text1').remove();
});
$('#x2').click(function(){
$('#text2').remove();
});
instead what I'm getting after the 2nd click is this:
$('#x1').click(function(){
$('#text2').remove();
});
$('#x2').click(function(){
$('#text2').remove();
});
so it's always the last element what the x buttons want to remove. My question is, why can my "num" variable stay "1" at the #x1, but not at the #text1?
My solution was to address the parent element instead:
$('#x' + num).click(function(){
$(this).parent('.container').remove();
});
I know, that there is the "live" function too, what I could use, and I wouldn't need to mess with id-s, but that just seems more heavy. Is that correct? Or I'm overcomplicating things too much without making it more efficent?
It's because num is global and you access it after you create second button. To fix this you can wrap your code with anonymouse self executing function:
(function(num) {
$('#x' + num).click(function(){
$('#text' + num).remove();
});
})(num);
or better use only one click
$('.parent').on('click', '.container > div', function() {
$(this).parent().remove();
});
Related
I have some code, http://jsfiddle.net/hucw940s/
which has a for loop.
before
<div id="container">
</div>
after
for (i = 1; i < 4; i++){
var showMe = $('<a href=# id="link' + i + '">')
.append('click').click(function(){ alert('You clicked num: ' + i) });
$('#container').append(
$('<div id="div'+i+'">').append('this is div number: ' + i).append(showMe)
);
}
so the links are generated with id=link1, link2, link3 etc, and the divs appended are the same, however the onclick code seems to put the var i in after the event, so on clicking any link they say "you clicked number 4"
How can I make this use the i from the clicked link inside the function that is called on click?
What you are experiencing is the expected behavior based on your code.
However, what you are actually trying to do is pass in event data to your click function. This can be accomplished like this:
for (i = 1; i < 4; i++) {
var showMe = $('<a href=# id="link' + i + '">').append('click')
.click({value: i}, function (e) { alert('You clicked num: ' + e.data.value) });
$('#container').append($('<div id="div' + i + '">').append('this is div number: ' + i).append(showMe));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
</div>
First, you have to assign the event data, so we pass in an object
{value: i} before we pass in the handler function.
Then, in the handler function, we assign the variable e to the
event, so we can access the data attribute.
Finally, you access the value that was passed in by referencing
e.data.value.
You can add as many event data objects as you want and reference them by name this way.
The reason your code is not working as you are expecting is because the variable i is already equal to 3 by the time the click event happens, since the for loop completes before you are able to click any of the links.
Hope this helps give you a better understanding of why your code is behaving the way it is and what you can do to fix it.
Store the id in a data-attribute.
Updated jsFiddle
I'm trying to pass a variable through from one page to another in my phone gap application. The function however, never seems to get called.
Heres what's building up the links:
$.each(data, function(index) {
$("#listpetsList").append("<li><a href='javascript:loadPetdialog(" + data[index].AnimalCode + ")' data-rel=\"dialog\" data-transition=\"flip\"><img src='" + data[index].Picture + "'><h2>" + data[index].Name + "</h2><p>Type</p></li>");
});
Heres the loadPetDialog:
var editingId = 0
function loadPetdialog(id) {
alert("hit");
editingId = id;
$.mobile.changePage("#select-pet-dialog");
}
However, it never seems to get hit
Don't use inline JavaScript with jQuery Mobile.
Do it like this:
$.each(data, function(index) {
$("#listpetsList").append("<li><a data-custom='"+ data[index].AnimalCode + "' data-rel=\"dialog\" data-transition=\"flip\"><img src='" + data[index].Picture + "'><h2>" + data[index].Name + "</h2><p>Type</p></li>");
});
$(document).on('click', '#listpetsList li a', function(){
editingId = $(this).prop('data-custom');
$.mobile.changePage("#select-pet-dialog");
});
var editingId = 0
Inline JavaScript has a tendency not to work or even misfire when used with jQuery Mobile. So it is best to bind click event to each listview element and get particular li element value when you click on it.
In my example I have bound click event to each listview elements. data[index].AnimalCode is saved as a custom data value. When you click on listview click event will trigger on selected listview element only, then we can easily find custom data value, add it to global variable and programatically change page.
Click event is bound in such way that it doesn't care if listview have or don't have inner content. It will work for any existing and future listview content.
Update
I made a working example out of your code: http://jsfiddle.net/Gajotres/92XG5/
There's only one difference between this code and last weeks example.
Change this line:
editingId = $(this).prop('data-custom');
To this line:
editingId = $(this).attr('data-custom');
I have a form where I add inputs dynamically. When I add a new input I increment a global id variable and concatenate it to the input's id so it will be unique. I also create a delete button for each input that should remove that input and himself (through removing the container <div> they are in). I do the remove process by adding an anonymous function to the delete button's click event via JQuery:
$('#deletebutton' + id).click(function(){
$('#inputcontainer' + id).remove();
});
The only problem with this solution that it isn't work in the way I excepted it. When I click any of the delete buttons it will delete the last input container because when I click, it executes the anonymous function and evaluate the id variable at that time, so the selected id will be the last input's id. So always the last input container will be deleted.
Is there a way to rewrite this function so when I add it to the click event, than it will evaluate the id, inject it and handle the selection as if it had been written like #inputcontainer1, #inputcontainer2, etc.
I can make this by adding the function's body to the button's onclick() event:
var newbutton = '<button id="deletebutton' + id + '" type="button" onclick="javascript:$(\'#inputcontainer' + id + '\').remove();">x</button>';
But is there a way doing this with the JQuery click() way?
To answer the specific question, you'd have to dig the id out of the DOM:
$('#deletebutton' + id).click(function(){
var id = $(this).attr("id").replace('deletebutton','');
$('#inputcontainer' + id).remove();
});
You could also store it as data when you create the delete button:
<button data-id="1" id="deletebutton1">
$('#deletebutton' + id).click(function(){
var id = $(this).data("id");
$('#inputcontainer' + id).remove();
});
Note that in both of these cases, id is a string, not an integer.
When I click any of the delete buttons it will delete the last input container [...]
If your 1st snippet is inside a loop, id probably isn't being scoped to each iteration. So, by the time one of the click() events is triggered and it's trying to use .remove(), id will have already been set to the last value given while looping.
You can use an IIFE to create an additional function scope for keeping a different id for each iteration (ref: closure).
/* loop */ {
var id = ...;
(function (id) {
$('#deletebutton' + id).click(function(){
$('#inputcontainer' + id).remove();
});
})(id);
}
Though, for future reference, ECMAScript 6 is adding block scoping which should allow for:
/* loop */ {
let id = ...;
$('#deletebutton' + id).click(function(){
$('#inputcontainer' + id).remove();
});
}
$('#deletebutton' + id).click(function(){
$(this).parent().remove();
});
If the container isn't a direct parent and doesn't have a class you could do:
$('#deletebutton' + id).click(function(){
var idNum = $(this).attr("id").replace('deletebutton','');
$("#inputcontainer"+idNum).remove();
});
If you've got appropriate classes (or can add them), this would be best:
$(document).on("click",".deleteButton",function() {
$(this).parents(".inputContainer").remove();
});
I have a website where user can select an item, the detail is then displayed, including the quantity. I have also included a button inside the div so that when clicked, it should decrease the quantity by 1.
$("#btnBuy1").click(function()
{
if (!sessionStorage['quantity1'])
{
sessionStorage['quantity1']=1;
}
else
{
sessionStorage['quantity1']++;
}
$("#dropbox").html('<div id = "1"><img class = "thumb" id = "t1" src="../images/birthday_metoyou.jpg" />' + teddy[1].desc + ", Price £"
+ teddy[1].price + ", Quantity: " + sessionStorage.getItem('quantity1') + "<button id = 'btnRemove1'>Remove</button></div><br/>");
updateBasket();
sessionStorage["total1"] = parseInt(sessionStorage.getItem('quantity1')) * teddy[1].price;
updateSubtotal();
if (Modernizr.sessionstorage)
{ // check if the browser supports sessionStorage
myids.push(teddy[1].partnum); // add the current username to the myids array
sessionStorage["ids"]=JSON.stringify(myids); // convert it to a string and put into sessionStorage
}
else
{
// use cookies instead of sessionStorage
}
});
$("#btnRemove1").click(function()
{
alert(remove);
});
I put in an alert message to see if the button is working properly, but when I click the btnRemove1 button, nothing happens.
Since the button is dynamically added, can you try:
$(document).on('click', '#btnRemove1', function() {
{
alert("remove"); //I dont know what remove was is the example, added quotes around it.
});
That is because the button is added later (dynamicly). You will have to use a delegate.
You don't have to use body for this. Any non dynamicly inserted element that is a parent of #btnRemove1 will do.
$('body').on('click','#btnRemove1',function(){
alert(remove);
});
The reason is that you bind the event before the element #btnRemove1 is present on your page. Therefore there is nothing to bind the event to. The body element however - will be present on the page and delegate your event to #btnRemove1.
You can either tie the event to the document (what jQuery live used to do before it was deprecated)
now it is:
$(document).on("click", "#btnRemove1", function(){})
or you can rebind the event after #btnRemove1 is added to the Dom.
Most likely, your Remove button isn't in the DOM before you try to attach the click event to it. It is hard to tell from your code snippets, but if the Buy button action hasn't completed successfully, then Remove won't exist.
At the point that you attach the click event to Remove, try console logging $("#btnRemove1").length to see if it exists, or use break points.
An improvement to your code would be to cache in a variable $("#dropbox") and then look for your buttons within it, as in:
var $dropBoxNode = $("#dropbox");
$dropBoxNode.find("#btnRemove1");
And you should use .on() instead of the deprecated .click().
Try putting the remove button click handler addition after you create the remove button
///Code snippit
$("#dropbox").html('<div id = "1"><img class = "thumb" id = "t1" src="../images/birthday_metoyou.jpg" />' + teddy[1].desc + ", Price £"
+ teddy[1].price + ", Quantity: " + sessionStorage.getItem('quantity1') + "<button id = 'btnRemove1'>Remove</button></div><br/>");
$("#btnRemove1").click(function()
{
alert(remove);
});
updateBasket();
///Code snippit
$('a.edit').on('click','a.edit',function(){
if (confirm("Are you sure you want to Edit this Photo?"))
{
....
....
}
});
Not Working When Data is Loading with AJAX on a DIV Area
Just Like
EDIT
I run this jQuery (1.8.3) code and always get the "in" alerted even when the length is greater than 1.
What I'm doing is dynamically adding elements to a menu and the if is to make sure this element doesn't exist yet.
I tried also == 0 and === 0 but the result is the same...
Here is a JS fiddle: http://jsfiddle.net/mHhwq/4/
$(".sidebarit a.olink").click(function(event){
iframe_url = $(this).attr("href");
sidebar_id = '#' + iframe_url.replace(/[/.]/g, '');
alert('sidebar_id: ' + sidebar_id);
// create the sidebar if it doesn't exist
if ($(sidebar_id).length < 1) {
alert("in");
$("#sidebar_nav ul").append('<li></li>');
$("#sidebar_content").append('<div id="' + sidebar_id + '" style="display:none;"></div></div>');
} else { alert("out"); }
// don't follow the link
event.preventDefault();
});
In FireBug I see the length equals 1 but still enters the block.
What am I doing wrong?
Update:
My mistake was that I added the # at the wrong place...
Try to put alert inside if stmt as alert($(sidebar_id).length).
And you are making a mistake in appending the div to$("#sidebar_content").
Where sidebar_id is something like #test from sidebar_id = '#' + iframe_url.replace(/[/.]/g, ''); and you are appending like <div id= "#test" there, where it should be <div id= "test"(No # symbol is requird for id).
Your code will results like
$("#sidebar_content").append('<div id="#test" style="display:none;"></div></div>');
Change to
$("#sidebar_content").append('<div id="test" style="display:none;"></div></div>');
Then try again.
You must not have more than one element with the same ID. jQuery takes just the first in such a case.
To prove this have such HTML:
<div id="mydiv">hello</div>
<div id="mydiv">world</div>
Then this code:
var myDiv = $("#mydiv");
alert("length: " + myDiv.length + ", contents: " + myDiv.html());
Test case.
If you have more than one element you need to iterate, use class instead or alternatively make sure to have unique ID for each sidebar and take the one closest to the clicked element.