jQuery dynamic checkbox event handling - javascript

When appending HTML from a JSON reply, the event handlers appear to lose their event bindings. In using the .live() function the handler now appears to work.
$.each(result[0], function(i,wellList) {
$jsonResult = wellList["#name"];
$uid = wellList["#uid"];
$dynamicCheckBoxDiv += '<input type="checkbox" name="checkbox-1" value="'+ $uid
+ '" class="wellCheck" id="checkbox-'+i+'" />' +
'<label for="checkbox-'+i+'">' + $jsonResult + '</label>';
});
$dynamicCheckBoxDiv += '</fieldset></div>';
//Append results to div
$("#dynamicCheck").append($dynamicCheckBoxDiv).page();
$(".wellCheck").live('click', (function() {
This event now fires when the click function is run. However, after clicking the checkbox a few times, it randomly associates the checks with the wrong boxes and starts to fire the click event fire on a single click. Has anyone seen this before?
Also: How could I add a method to check all the boxes in a separate button? Since they are being added dynamically it seems to just bypass this function:
// When select No wells is clicked this method is run
$('#selectNone').click(function() {
$('#dynamicCheck .wellCheck').find(':checkbox').attr('checked', 'checked');
});
It enters the method, but doesnt seem to check any of the boxes. I have jQuery and jQuery mobile added to this page and both methods exist under document.ready.

You don't need to find(":checkbox") since the .wellCheck element is the checkbox. Just do this:
$("#selectNone").click(function(){
$("#dynamicCheck .wellCheck").prop("checked", true);
});
Demo.

Explanation of the first bit is that the written-into-HTML listeners only apply on page load. Any time you're adding raw HTML to the page, you have to set any listeners specifically. Similarly, just changing the "onclick" attribute does nothing to the listeners.
I suspect your problem with the second bit has something to do with the fact that, at least by my reading, '$(".wellCheck").live(...)' is going to affect every box you've created thus far each time. You might be better served by something like '$dynamicCheckBoxDiv.live(...)'
I'm not entirely clear on the precise syntax - I worked more with cloned HTML rather than manually constructed, so you may need an intervening step to render it into a DOM object or something (if it's not one already) - but I suspect something like this will help.
Also, you might wish to use '.click(...)', rather than '.live("click", ...)'.

You should use delegate not live:
$("#dynamicCheck").delegate('.wellcheck','click', function(){
//stuff on click
});
This would be better bound at that scope than at the body which is what live does.
EDIT: See this for some examples of checkbox management: http://jsfiddle.net/h682v/3/
That uses older attr() and should use prop() instead but the principle remains.

Related

Using .jquery .on() without an event

I have input elements that get appended to my HTML document that I need to get the value of. I understand that .on() should be used to get appended elements, but .on() expects an event to activate it, and I don't need an event.
Below is the code. #save_design is on a different part of the page. #fields_cnt is the parent that holds all my appended forms. .reg_field is the element I'm trying to get the value of. The first child works because that form is present when the document is loaded, or in other words, it is not appended. The other children all returns values undefined, or false depending on the input type and the logic I'm applying to it. This leads me to believe that .on() or something close to it should be used.
To clarify, I am trying to get the value of an appended input when #save_design is clicked.
$('#save_design').click( function() {
group_text[form_count] = $('#fields_cnt .field_group:nth-child(' + child + ') .reg_field').val();
I have tried replacing the originating click event as so. It has not worked.
$('body').on('click', '#save_design', function(){
I have tried using .on() without an event or event object. It has also not worked.
$('body').on('', '', function(){
group_text[form_count] = $('#fields_cnt .field_group:nth-child(' + child + ') .reg_field').val();
});
I have found a plugin that should work.
JQuery selecting dynamically generated html without adding event (with live)
This is not ideal, because as stated in the github readme, it is being rewritten. Also, the SO answer is 3 years old now, so it may no longer be the correct answer.
https://github.com/brandonaaron/livequery
I'd like to find a more direct solution. Is there a way to do this natively in jQuery? Is there a way to use .on() without an event, and if so, what's the appropriate syntax?
UPDATE: Clarification: The input fields get appended when an add field button is pressed. Their values change after they are appended. I would prefer not to rerecord the value of an input, every time it is altered.
UPDATE Here is the HTML structure to give a better idea of how I'm defining child.
<div id="fields_cnt">
<div id="field_group_1" class="field_group form-group">
<input placeholder="Field" class="reg_field form-control" />
</div>
<!-- This is appended by jQuery. There may be multiple of these -->
<div id="field_group_2" class="field_group form-group">
<input placeholder="Field" class="reg_field form-control" />
</div>
</div>
I have found a great solution to my problem. It takes a different approach on selecting the element, but ultimately works and results in drier code.
Here, I use each, to grab each instance of the appended element I am trying to select. This returns the desired value.
$('.reg_field').each( function() {
group_text[form_count] = $(this).val();
form_count++;
});
I suspect the issue was my previous selector was unable to use $(this), which seems to work in more cases for appended elements. Another possibility that was brought up in the comments was the use of nth-child in the middle of a selection. I am not sure on these points, and would appreciate a better explanation. Hopefully this will help for someone who faces the same issue. Also, I appreciate the help on getting me to focus on the selection rather than the binding.

jquery onclick is not working

I am dynamically creating a link, and I am trying to add a click function to it. The links are being added, but the click function is not working. I dont see anything in the console, nor do I get an alert.
var section = $('<section></section>').append('<a class="link" href="#"></a>');
section.find('a.link').attr('title', post.data.permalink)
.text(post.data.title)
.click(function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
items.push(section[0].outerHTML);
$('#posts').empty().append(items.join(''));
One of the most common mistakes with jQuery. When dynamically adding elements, normal jQuery event handlers don't work, so you need to use .live() to be able to bind events to dynamic elements. This should work:
var section = $('<section></section>').append('<a class="link" href="#"></a>');
section.find('a.link').attr('title', post.data.permalink)
.text(post.data.title)
.live("click", function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
items.push(section[0].outerHTML);
$('#posts').empty().append(items.join(''));
Notice the use of .live("click", function() { ... }); there? That should solve your problem.
That looks okay. You may try using each() to iterate over that collection. I'm not sure if you can bind even handlers to a jQuery collection like that.
section.find('a.link').each(function(){
$(this).attr('title', post.data.permalink)
.text(post.data.title)
.click(function()
{
console.log("function");
alert("hi");
getThread(post.data.permalink);
});
});
If running this in IE be sure that developer-tools (F12 )are present , otherwise console will be undefined and the call of console.log() will force an error and stops the function from executing.
What else: outerHTML is IE-only, you'll better forget it and never use it.
You don't need to manually join the HTML.
You're binding the event to an element, then taking the HTML of that element and just concatenting it into a string, which is then in turn inserted into the DOM as new elements when you append to #posts.
items is not defined here, but I'm going to go out on a limb and assume it's an array of generated <section>s and etc?
If that's the case, I might be missing something you're trying to do here, but it seems you could just eliminate the whole concatention of HTML and simply append the items array, which would preserve the bound click event.
// Push the element, don't stringify it.
items.push(section);
// Then simply append the "items" elements.
$('#posts').empty().append(items);
Sure, live would probably solve the problem as well, but you certainly can bind events to generated elements then insert them into the DOM. What you cannot do is bind an event to an element then print out it's HTML and insert that into the DOM. Any binding you made with the original element is lost.

Using jQuery to select checkboxes with click events

Is there a way to use jquery to select all checkboxes on a page that have an associated click event? I considered adding a class, for instance HasClickEvent, that I could use to identify such classes, but I am editing a huge script where click events are sporadically added all over the place and I think this would probably end up being messier, so a single jQuery call would be perfect
jQuery.each($('input[type=checkbox]').data('events'), function(i, event){
jQuery.each(event, function(i, handler){
if(handler.type.toString() == 'click')
{
// do something
}
});
});
To check all
$('.checkbox').attr('checked','checked'); // checkbox is the class for all checboxes to be selected change it with our own
To deselect all
$('.checkbox').removeAttr('checked');
A quick google reveals this plugin, but it's pretty old. You may be able to read the code and see how they are achieving it though :D
If the click events are attached using the onclick attribute (instead of added dynamically via JavaScript/jQuery), you can do it like this:
$("input[type=checkbox][onclick]").each(function() {
//All returned elements have an onclick attribute
});

JQuery click anywhere except certain divs and issues with dynamically added html

I want this webpage to highlight certain elements when you click on one of them, but if you click anywhere else on the page, then all of these elements should no longer be highlighted.
I accomplished this task by the following, and it works just fine except for one thing (described below):
$(document).click(function() {
// Do stuff when clicking anywhere but on elements of class suggestion_box
$(".suggestion_box").css('background-color', '#FFFFFF');
});
$(".suggestion_box").click(function() {
// means you clicked on an object belonging to class suggestion_box
return false;
});
// the code for handling onclicks for each element
function clickSuggestion() {
// remove all highlighting
$(".suggestion_box").css('background-color', '#FFFFFF');
// then highlight only a specific item
$("div[name=" + arguments[0] + "]").css('background-color', '#CCFFCC');
}
This way of enforcing the highlighting of elements works fine until I add more html to the page without having a new page load. This is done by .append() and .prepend()
What I suspected from debugging was that the page is not "aware" of the new elements that were added to the page dynamically. Despite the new, dynamically added elements having the appropriate class names/IDs/names/onclicks ect, they never get highlighted like the rest of the elements (which continue to work fine the entire time).
I was wondering if a possible reason for why my approach does not work for the dynamically added content is that the page is not able to recognize the elements that were not present during the pageload. And if this is a possibility, then is there a way to reconcile this without a pageload?
If this line of reasoning is wrong, then the code I have above is probably not enough to show what's wrong with my webpage. But I'm really just interested in whether or not this line of thought is a possibility.
Use .live to "Attach a handler to the event for all elements which match the current selector, now and in the future". Example:
$(".suggestion_box").live("click", function() {
// means you clicked on an object belonging to className
return false;
});
Also see .delegate, which is similar.
Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will always propagate to the element to which they are delegated; event handlers on any elements below it will already have been executed by the time the delegated event handler is called.
from the jQuery documentation =)
(only to explain better why #karim79 also suggested the delegate method ;P )

How to work with dynamically created fields?

I have web layout, which can contains several links on it. Those links are dynamically created, using AJAX functions. And it works ok.
But, I don't know how can I work with those "dynamically created links" (ie. how to call some JS or jQuery function if I click on them). I guess that browser can not recognize them, since there are created after page is loaded.
Is there some function, that can "re-render" my page and elements on it?
Tnx in adv on your help!
You can use the 2 following methods jQuery provides:
The first one, is the .live() method, and the other is the .delegate() method.
The usage of the first one is very simple:
$(document).ready(function() {
$("#dynamicElement").live("click", function() {
//do something
});
}
As you can see, the first argument is the event you want to bind, and the second is a function which handles the event. The way this works is not exactly like a "re-rendering". The common way to do this ( $("#dynamicElement").click(...) or $("#dynamicElement").bind("click", ...) ) works by attaching the event handler of a determinate event to the DOM Element when the DOM has properly loaded ($(document).ready(...) ). Now, obviously, this won't work with dynamically generated elements, because they're not present when the DOM first loads.
The way .live() works is, instead of attaching the vent handler to the DOM Element itself, it attaches it with the document element, taking advantage of the bubbling-up property of JS & DOM (When you click the dynamically generated element and no event handler is attached, it keeps looking to the top until it finds one).
Sounds pretty neat, right? But there's a little technical issue with this method, as I said, it attaches the event handler to the top of the DOM, so when you click the element, your browser has to transverse all over the DOM tree, until it finds the proper event handler. Process which is very inefficient, by the way. And here's where appears the .delegate() method.
Let's assume the following HTML estructure:
<html>
<head>
...
</head>
<body>
<div id="links-container">
<!-- Here's where the dynamically generated content will be -->
</div>
</body>
</html>
So, with the .delegate() method, instead of binding the event handler to the top of the DOM, you just could attach it to a parent DOM Element. A DOM Element you're sure it's going to be somewhere up of the dynamically generated content in the DOM Tree. The closer to them, the better this will work. So, this should do the magic:
$(document).ready(function() {
$("#links-container").delegate("#dynamicElement", "click", function() {
//do something
});
}
This was kind of a long answer, but I like to explain the theory behind it haha.
EDIT: You should correct your markup, it's invalid because: 1) The anchors does not allow the use of a value attribute, and 2) You can't have 2 or more tags with the same ID. Try this:
<a class="removeLineItem" id="delete-1">Delete</a>
<a class="removeLineItem" id="delete-2">Delete</a>
<a class="removeLineItem" id="delete-3">Delete</a>
And to determine which one of the anchors was clicked
$(document).ready(function() {
$("#links-container").delegate(".removeLineItem", "click", function() {
var anchorClicked = $(this).attr("id"),
valueClicked = anchorClicked.split("-")[1];
});
}
With that code, you will have stored in the anchorClicked variable the id of the link clicked, and in the valueClicked the number associated to the anchor.
In your page initialization code, you can set up handlers like this:
$(function() {
$('#myForm input.needsHandler').live('click', function(ev) {
// .. handle the click event
});
});
You just need to be able to identify the input elements by class or something.
How are these links dynamically created? You can use use the correct selector, given that they are using the same class name or resides in the same tag, etc.
consider the html form
<form>
<input type="text" id="id" name="id"/>
<input type="button" id="check" name="check value="check"/>
</form>
jquery script
$('#check).click(function() {
if($('#id).val() == '') {
alert('load the data!!!!);
}
});
here on clicking the button the script check the value of the textbox id to be null. if its null it will return an alert message....
i thin this is the solution you are looking for.....
have a nice day..
Noramlly , the browser process response HTML and add it to DOM tree , but sometimes , current defined events just not work , simply reinitialize the event when u call the ajax request ..
All you need to do to work with dynamically created elements is create identifiers you can locate them with. Try the following code in console of Firebug or the developer tools for Chrome or IE.
$(".everyonelovesstackoverflow").html('<a id="l1" href="http://www.google.com">google</a> <a id="l2" href="http://www.yahoo.com">yahoo</a>');
$("#l1").click(function(){alert("google");});
$("#l2").click(function(){alert("yahoo");});
You should now have two links where the ad normally is that were dynamically created, and than had an onclick handler added to bring up an alert (I didn't block default behaviour, so it will cause you to leave the page.)
jQuery's .live will allow you to automatically add handlers to newly created element.
If your links are coming in via AJAX, you can set the onclick attributes on the server. Just output the links into the AJAX like this:
Holy crap I'm a link
The return false makes sure the link doesn't reload the page.
Hope this helps!

Categories