Dynamically generated html elements stop working - javascript

In the following code I have some comments in an array which are displayed in a div using jQuery. Each comment has an options button which works fine until I post a new comment. I tried using unique IDs for each element but it didn't work either.
When the page loads, the options buttons work; but when I submit a new comment, none of the buttons work. What am I doing wrong?
Here's my script:
var i = 0;
var comments_display= "";
var comments = ['Hello World!', 'Hello! This is a comment.'];
//reads the entire array, creates the content, and sends it to the div
function show_comments(){
for (i=0; i<comments.length; i++){
comments_display += "<div class='single_comment_container'>";
comments_display += "<div class='comment_comment'>" + comments[i] + "</div>";
comments_display += "<div class='options'>Options</div></div>";
}
$("#comment_container").html(comments_display);
comments_display = "";
}
//appends a new comment to the array
function new_comment(){
if ($("#comment_input").val() == null || $("#comment_input").val() == ""){
alert("Your comment must be at least 1 character long.");
}
else{
comments.push($('#comment_input').val());
show_comments();
$("#comment_input").val("");
}
}
$(document).ready(function(){
show_comments();
$("#submit_comment").click(function(){
new_comment();
});
//display a message when an element of the class 'options' is clicked
$(".options").click(function(){
alert("OPTIONS");
});
});
And here's a fiddle to see how it works. http://jsfiddle.net/fahKb/3/
Thank you for taking your time to read this question.

You need to use delegation:
$(document).on( 'click', '.options', function() {
alert("OPTIONS");
});
http://api.jquery.com/on/
Note: You might want to use a static element other than document. (Some parent div that's always on the page or something.)

Just because you are adding elements dynamically so click won't work on those, so you have to find the closest existing parent on the page, here in your case is this comment_container and use the .on() handler: http://jsfiddle.net/fahKb/4/
$('#comment_container').on('click',".options",function(){
alert("OPTIONS");
});

$(document).on( 'click', '.options', function() {
alert("OPTIONS");
});
This first response is right, the cause of this is that when elements are loaded into the DOM you assign event listeners. Essentially saying hey if this is 'clicked' then do something. The problem is that when adding a new element you have NOT also added the event listeners. By doing something like the above code, essentially what you're doing is a search for everything within document that then has the class of ".options" and finally if it is clicked then acting and executing some code.
With that said using document isn't the most optimum method but it is sometimes necessary. A better solution would be if you were to wrap all the comments in say a "div" or some other element then pass that in place of document. This will instead of searching the entire document for the '.options', it would only search your wrapper eliminating alot of unnecessary work.
$('.commentWrapper').on( 'click', '.options', function() {
alert("OPTIONS");
});

Related

jQuery: create a div alert you when its is clicked,

I can't put a title to it. It's inception :)...
I have add div, when it is clicked, it creates alert div. When alert div is clicked it alert me.
that is an example.
$("#add").click(function(){
$("#add").after("<div class='alert'>Alert</div>");
});
$(".alert").click(function(){
alert("Here I am");
});
I noticed if I placed a div in the html template as <div class="alert">Alert</div> the alert will work. But if I added the div through the jQuery/JS it will not work.
what is the point of that?
to add more inputs and remove it in case he/she added too much, I noticed it didn't work and I wanted to know why:
this is the actual code:
$(document).ready(function(){
var i = $("#new_field_count").val();
//add new field
$("#addnew_field").click(function(){
i++;
$("#new_field").before("<div class='fivepadding'><input name='part1_" + i + "' type='text' placeholder='<?=lang('addform_p1')?>'> = <input name='part2_" + i + "' type='text' placeholder='<?=lang('addform_p2')?>'> <span class='remove clickable'><?=lang('addform_field_remove')?></span> </div>");
$("#new_field_count").val(i);
});
// remove the field
$(".remove").click(function(){
i--;
$(this).parent('div').remove();
$("#new_field_count").val(i);
});
});
For dynamically created content, use on.
$("#wrapper-div").on("click", ".alert", function(){
alert("Here I am");
};
Additionally, it's worth mentioning that it is adviced to use on instead of clickfor monitoring for example classes.
Rather than adding an event handler to every class element separately, the click event will bubble to the parent. According to the jQuery docs, it is a good idea to attach the handler to the closest relevant parent element (rather than the document).
Your document.ready block is interpreted once the DOM has finished loading. At that point in time, anything not in your DOM cannot have proper event binding. Here you can use delegation to make sure your bindings are going as planned. Since your 'body' will be loaded, you can target your .alert div for clicks as follows:
$("body").on("click", ".alert", function(){
alert("Here I am");
};

How to use jQuery to check if an element is added to page?

So I am using endless scrolling, and when I have scrolled x amount of pixels there will be added new objects to the page. But how can I use jQuery to check if a new element (class or id) is added to the page?
(I want to check this, because if a new element is added I want to do some jQuery on the new element).
Just use .length, to check if it exists, after an append()
$('#elemId').length;
Like so...
if($('#elemId').length > 0){ //your code here };
Or write your own function....
jQuery.fn.Exists = function(){
return jQuery(this).length > 0;
};
Then use it to return true or false...
if($('#elemId').Exists()){ //your code here };
Or you can use the livequery() plugin...
$('#elemID').livequery(function()
{
// do things here like binding new events and stuff.
// this function is called when an object is added.
// check the API for the deletion function and so on.
});
I can't seem to find the plugin anymore, on the jQuery website, but it did exist at one point
You can also try DOMNodeInserted...
$(document).bind('DOMNodeInserted', function(e) {
console.log(e.target, ' was inserted');
});
You can use on()....if your selector will always be the same...
So for instance, say as you scroll you're always adding a new div called class="newDiv"....
Then the jquery you want to perform....if you want to bind an event to click...
$(document).on( 'click', '.newDiv', function(){ //your code here
});

Adding jQuery event handlers to elements with wildcard IDs

I currently have the following in a document.ready block:
$("[id^=summaryDetailLink_]").each(function(index) {
var splitID = this.id.split("_");
this.click(alert('clicked: '+splitID[1])); //toggleDetail(splitID[1])
});
Ultimately I want to detect when a TD with an ID of "summaryDetail_" is clicked on and fire the toggleDetail function with the ID taken from the TD.ID attribute.
The above seems to generate the correct ID (the alert popsup) but is firing when the page loads rather than when I click on the element.
So problem number 1 - why is it firing on page load rather than creating a handler for click on each element and waiting for that click?
Problem number 2, in reading around this issue it seems it would be more sensible to create a single event handler on the table rather the TD then determine which TD element was clicked. How would I convert the code to do that?
Answer to first question:
$(function() {
$("[id^=summaryDetailLink_]").click(function() {
var splitID = $(this).id.split("_");
alert('clicked: '+splitID[1])
});
}
Answer to second question, you can do this:
$('table#yourtable').on('click', '[id^=summaryDetailLink_]', function(e) {
var splitID = $(this).id.split("_");
alert('clicked: '+splitID[1])
});
I think you're misunderstanding how the click handler works:
$(function() {
$("[id^=summaryDetailLink_]").click(function() {
var splitID = $(this).id.split("_");
alert('clicked: '+splitID[1])
});
}

how to remove all ClientEvents from anchors in an HTML String with jQuery

I've been struggling with what seems to be a simple problem for a few hours now. I've written a REGEX expression that works however I was hoping for a more elegant approach for dealing with the HTML. The string would be passed in to the function, rather than dealing with the content directly in the page. After looking at many examples I feel like I must be doing something wrong. I'm attempting to take a string and clean it of client Events before saving it to our Database, I thought jQuery would be perfect for this.
I Want:
Some random text click here and a link with any event type
//to become:
Some random text click here and a link with any event type
Here's my code
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv).find('a').unbind();
return $(myDiv).html();
}
My results are, the onClick remains in the anchor tag.
Here's a pure Javascript solution that removes any attribute from any DOM element (and its children) that starts with "on":
function cleanHandlers(el) {
// only do DOM elements
if (!('tagName' in el)) return;
// attributes is a live node map, so don't increment
// the counter when removing the current node
var a = el.attributes;
for (var i = 0; i < a.length; ) {
if (a[i].name.match(/^on/i)) {
el.removeAttribute(a[i].name);
} else {
++i;
}
}
// recursively test the children
var child = el.firstChild;
while (child) {
cleanHandlers(child);
child = child.nextSibling;
}
}
cleanHandlers(document.body);​
working demo at http://jsfiddle.net/alnitak/dqV5k/
unbind() doesn't work because you are using inline onclick event handler. If you were binding your click event using jquery/javascript the you can unbind the event using unbind(). To remove any inline events you can just use removeAttr('onclick')
$('a').click(function(){ //<-- bound using script
alert('clicked');
$('a').unbind(); //<-- will unbind all events that aren't inline on all anchors once one link is clicked
});
http://jsfiddle.net/LZgjF/1/
I ended up with this solution, which removes all events on any item.
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv)
.find('*')
.removeAttr('onload')
.removeAttr('onunload')
.removeAttr('onblur')
.removeAttr('onchange')
.removeAttr('onfocus')
.removeAttr('onreset')
.removeAttr('onselect')
.removeAttr('onsubmit')
.removeAttr('onabort')
.removeAttr('onkeydown')
.removeAttr('onkeypress')
.removeAttr('onkeyup')
.removeAttr('onclick')
.removeAttr('ondblclick')
.removeAttr('onmousedown')
.removeAttr('onmousemove')
.removeAttr('onmouseout')
.removeAttr('onmouseover')
.removeAttr('onmouseup');
return $(myDiv).html();
}

JQuery ajax and dom issue

I am using JQuery to add a row to a table. Within the row is an element who's click event I am capturing:
$(document).ready(function() {
var newRow = "<tr> ... </tr>";
$('tableName > tbody:last').append(newRow);
$(...).click( function() { // click event on newly inserted elem in the row
alert("click");
});
}
This works great and the alert comes up as expected. BUT when I now add the new row dynamically via an ajax call and parsing the xml, it stops working:
$(document).ready(function() {
getData();
$(...).click( function() { // click event on newly inserted elem in the row
alert("click");
});
function getData() {
$.ajax({
...
success: function(data) {
//parse the xml
$('tableName > tbody:last').append(parsedXml);
}
});
}
The html is correctly added to the DOM, but the click event is no longer captured. Is there some issue with scope or closures going on here?
use
$(...).live('click', function() { // click event on newly inserted elem in the row
alert("click");
});
This keeps the click event running after it has been used
more info
When working with a table, I like to use .delegate() for this. It's very similar to .live(), but lets you set up an event listener on a single parent element, rather than individual handlers on every child element. So whether you have a table of one row or 1000, you still need only one handler.
$('#yourtable').delegate('your_descendant_element','click', function(){
alert("click");
});
You should look into using the live() event handler. It allows you to create an event that matches elements created in the future dynamically, which is what is not happening right now. Another way to fix it would be to move the all to bind down below where you append the new table row, but live() is a much better answer.

Categories