I am writing a script using jQuery to add multiple control boxes(divs) to a web page. These divs contain controls (anchors) like close, prev, next, search etc. A code sample:
$div_overlay =
$('<div></div>')
.addClass('overlay')
.append($('<div></div>')
.addClass('text_controls')
//The onClick method below works perfect but not .click() of jQuery(due to the way 'index' is used)
.append($('<a onClick="overlay_hide('+index+'); return false;"></a>')
.addClass('close')
.attr('href','#')
/*.click(function(){
//The 'index' gets incremented as divs are created and hence a wrong value(the last one) is passed irrespective of the div clicked
overlay_hide(index)
})*/
)
'index' is a global var to keep track of the 'overlay' divs created.
It is incremented as the divs are created and each div is pushed in an array as it is created. So, 'index' is basically the array index of a div.
To keep it simple, I only added the 'close' anchor. The $div_overlay is in a function which is called every time an image is clicked.
My problem is to handle the click events for the anchors like 'close'. I would like to identify the div for which the anchor is clicked using an 'index' which is a global var.
I would like to be able to pass a reference to the div on which the close action is performed. If I use the jQuery click method which is commented in above code to close the div, it passes the last index value as the parameter to overlay_hide() (since index is incremented as the divs are created). If I use the onClick method as above, it works fine by passing the correct index value.
So, how do I identify these divs using indexes and be able to uniquely access them based on which div control is clicked? (Probably objects need to be used but I am not sure.)
One way would be to get the parent of the clicked anchor but I do not want to do it that way and would like to use an index.
You could add meta data to the anchor with a data attribute.
$('<a data-index="' + index + '"></a>').click(function(){
var data = $(this).data();
overlay_hide(data.index); // note index will be a string
return false;
});
Another way you could do it is with a closure on the click function:
$('<a />').click(function(i){
return function(e){
// use i here this is the callback.
overlay_hide(i);
return false;
};
}(index));
I would also like to point out that you have an id .attr('id','overlay') being added - and id's must be unique across the DOM.
You should read about closures and scope in JS: http://bonsaiden.github.com/JavaScript-Garden/#function.closures
Quick fix to your problem:
var closeButton = (function(index){
return $('<a></a>').addClass('close').attr('href','#').click(function(){
overlay_hide(index);
})
})(index);
var $div_overlay = $('<div></div>').attr('id','overlay').append(
$('<div></div>').addClass('text_controls').append(closeButton)
)
It'd be so much easier to just use the "overlay" class that's on the container:
$('body').delegate('a.close', 'click', function() {
$(this).closest('div.overlay').hide();
});
Just set that up, and things like it for the other types of control, and then you don't have to worry about sticking those ugly DOM0 handlers in your added tags at all.
I know you said you "don't want to do it that way", but unless you can explain why such an exercise is valuable in general, it seems unethical not to recommend the most obvious way to go about solving the problem.
I think you need to use the live() function, read this:
http://api.jquery.com/live/
Related
I have a function that dynamically creates div elements based upon whatever input is given, and lets them choose certain items by clicking on each div. I have it so that if the div is clicked, a function (named checkToggle) is called that makes it looks like it is selected and adjusts some related variables. There is a checkbox in the div element that is toggled by this function (hence its name). Long story short, I had to jump through some hoops to get it to work, most of which I don't even remember. Please don't ask me about that.
The point of this question is this. I initially used the following JavaScript code to run the function when the checkbox was clicked. It was assigned by the main function, which created these div elements using a for loop.
document.getElementById(`${itemID}-checkbox`).onclick = function() {
checkToggle(`${itemID}-checkbox`);
};
This works, but I wanted to try to convert all of my onClick functions to JQuery. Here is the JQuery alternative I created.
$(`${itemID}-checkbox`).on(`click`, function() {
checkToggle(`${itemID}-checkbox`);
});
While the code itself seems to be fine, it does not work. It seems as if JQuery functions cannot be created like this in a for loop or something. It is applied after the element is created and put in its place, so I don't think it has anything to do with the element not being ready. I am also having the same issue with 2 other similar cases. Any idea as of why this isn't working?
Let me know if more information is needed and if so, what kind of information is needed.
You need to update the selector to Target HTML id using the # character. Simply prepend the character to the query:
$(`#${itemID}-checkbox`).on(`click`, function() { checkToggle(`${itemID}-checkbox`); });
It would also apply to DOM methods querySelector or querySelectorAll as well.
Hopefully that helps!
I have researched on the web and tested for a solution for quite a while, but have not been able to make this work. So I have decided to create a post here, even though its probably low-skilled and I'll get downvoted for it I have put a lot of effort and I hope someone can help out.
My code at the moment uses .click() function from JQuery and my goal is to use it on a button so that when I click that button, it checks whether the id of the button clicked on matches a variable that I set in the .js file. In other words, check if the thing I clicked on's id is equal to my "target".
This is the part of the code with the problem:
var target = '#vig_but_inc';
$(this).click(function() {
if(this.id == target) {
vigor.incStat(); // increase stats once
console.log("hi"); // test if code fires
$('#vig_res').html(vigor.current);
}
});
Please note I have checked if the code works without matching the id, without the if-statement - in that situation if I click on a specific, preset button's id I managed to increase the value of #vig_res which is my goal.
However with the if involved, as explained prior, I am trying to match what is being clicked on with my target, which is the id name I wish it to match to. I'm using this to check my click, which has worked in other areas but doesn't seem to work in this context.
I have made the variable target global scope as explained here in the comments: Check if the clicked div id matches with variable. It still doesn't work.
I know and have tested $(this).click(.., where it would fire off the code inside of whatever div I clicked. So I believe the problem lies afterwards, maybe in the this.id, but I've also used .is() like suggested elsewhere but it won't work that way either.
I hope someone can give me some insight into how to tackle this problem, thank you.
The answer is a little more complicated, in the anonymous function which is called when the click is triggered, this is not the clicked element, it is a jQuery object. You should accept as first parameter event and use event.target. Plus, target should not contain the #, because the .id returns only the name.
So, your code should look like this:
var target = 'vig_but_inc';
$(this).click(function(event) {
console.log(event.target);
if(event.target.id == target) {
vigor.incStat(); // increase stats once
console.log("hi"); // test if code fires
$('#vig_res').html(vigor.current);
}
});
Working Fiddle: https://jsfiddle.net/e8np0g9j/3/
Use the id and class selected before calling the click function like
$('.class').click(function() {});
So I may be approaching this wrong as I am learning but I can't seem to figure out what I am doing wrong here (probably simple mistake but I am having trouble). So I am trying to have a within the markup, a button click that allows selection from dialog and the submit button on the dialog includes call to custom function that does some logic then appends string to the like:
buildListElementItem += "<li>something</li>";
$("#my-list").append(buildListElementItem);
then bind click because i need each of these list items to be representative of a selection panel type thing
$("#my-list li").bind('click', function () {
//processing stuff
});
everything works fine but if I add more than one item to this list (one after another) and you click a single item, it rolls through each one, which confused me because there is no each and I think this should only add it to a single item....
so there is a bunch more to this function/etc but I think my approach right here is wrong??
I have tried modifying the selector to like a class that I add in the string for the li, I have tried using .on, .live, .delegate or anything I could find instead of bind click.
Perhaps this is simple approach type error to trying to perform this but I would great appreciate any help, advice, etc on this.
EDIT: just adding more for clarification
Dialog allows users to select item from select/drop down, and button click (jquery ui) has function that calls below idea to add the item to a list element, which serves as selection panel. So they can populate items needed on panel, then click each item to populate and associate data with that item.
function addNewListItem(passedType)
{
var buildListElementItem = "<li>" + passedType + "</li>";
$("#my-list").append(buildListElementItem);
$("#my-list li").bind('click', function () {
otherStuff();
});
if I do the above I am guessing that this cause every element to get binded over and over again? not sure, but this works with the exception that when I click a single li item on that panel, it processes for all li items on the panel (otherStuff function). So I think from the examples I am starting to understand the issue or why this won't work, but how would I approach what I am trying to do then? always appreciated guys!
}
When you say "there is no each", you omit that $("#my-list li") is a jQuery selector, i.e. it returns all the elements that match the expression: in this case, all the li items within the child tree of #my-list.
Thus, when you call bind, it is going to bind to each li item that has already been added to the element.
What you are looking for is something along this:
buildListElementItem = $("<li>something</li>"); //constructs a jquery object you can bind to
buildListElementItem.bind('click', function () {
//processing stuff
});
$("my-list").append(buildListElementItem);
This way, you bind before the element has been added.
i have four divs with the eventlistener onclick,
calling a js function which just does the following :
this.parentNode.removeChild(this);
i expect it to remove the div i clicked on, but it does not.
instead it deletes the last child and changes the id given after to the
id of the removed child (first click, the last child) and by further clicking on the
other divs counts down the given id to one. removing
the childNodes in the array from the last to the first.
i tried a lot of variants, for example
document.getElementById('parentElementName').removeChild(this.gettAttribute('id'));
or
parent =document.getElementById('parentElementName');
to_be_removed = document.getElementById(this.gettAttribute('id');
parent.removeChild(to_be_removed);
or with childNodes // id = 1,2,3,4
to_be_removed =document.getElementById('box_content').childNodes[this.getAttribute('id')];
parent =document.getElementById('box_content');
parent.removeChild(to_be_removed);
strange i can successfully change the visibility or the backgroundColor:
document.getElementById('box_content').childNodes[this.getAttribute('id')].style.visibility='hidden';
or
Managed to remake what you intended, go to http://jsfiddle.net/6YHcv/ to check it out. Is this what you needed?
If you are on IE and use attachEvent, this in the event handler would probably refer to the global object, not your element. Otherwise I can't tell why your code isn't working.
I see a few typos in your code. Your second example should work just fine, I think (see comments):
// make sure this is the parent element's ID and not the name, as this suggests.
parent = document.getElementById('parentElementName');
//note the double 't' in getAttribute; also, you are missing an end bracket
to_be_removed = document.getElementById(this.gettAttribute('id');
//looks good
parent.removeChild(to_be_removed);
Check out this example too, though: jsfiddle
It should be as simple as calling the function this.parentNode.removeChild(this) after an onclick handler.
I have a form that I am trying to alter with jQuery. Basically, my form has two elements and I need to change the value of the first option in each of them. However, there is an "add more" option that uses AJAX to dynamically generate another element that also needs changed. This add more button can be clicked an unlimited amount of times.
Right now I have this:
$(document).ready(function(){
$("#myname-0-field option:first").val("None");
$("#myname-1-field option:first").val("None");
});
This works fine, but once the "add more" button is clicked, I have more elements called "#myname-2-field", "#myname-3-field", "#myname-4-field" etc. These obviously aren't affected by adding another line into my jQuery as the document has already loaded when they are added.
So the real question is, can someone point me in the right direction of writing a function that can react when the new element is added and change it. If possible, I'm also looking for the function to be aware and look for "#myname-X-field option:first" for tidyness.
use live() function
Then using each function set value
From the jQuery API look live function
Maybe you could add class to your element, so that finding particular element would be easier and it would not add event to other similar elements.
In the example I have a Li with class
$('li.myClass').live('click', function() {
$(this).val(); // this is the getter for clicked value
$(this).val("some_value_here"); // this is the setter for clicked value
});
Now you can add more elements (that has myClass class) and it will have a click event.
Btw. if you know that all elements are inside some container (div for example) then you can write more efficient jQuery using delegate.
$('#container_id').delegate('li.myClass', 'click', function () {
});
This is more efficient because it looks your new elements only under "containter" not from the whole DOM structure.