JQuery ajax and dom issue - javascript

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.

Related

Jquery replaceWith() inside loop with click events

im trying to replace various elements with another inside a jquery .each loop and give them on click events to their child nodes, but it does not work, here is my code.
var replacer = function () {
var elementbody = "<div class='Container'><div class='Button'></div></div>";
$('.myclass').each(function (index, element) {
$(element).replaceWith(elementBody);
$(element).find('.Button').click(function () {
//------------------To do on click event------------------//
});
};
After you use
$(element).replaceWith(...);
element still refers to the old element, not the elements that have replaced it. So $(element).find('.Button') doesn't find the button you just added.
Instead of adding the handler to each element that you add, use delegation to bind a handler just once, as explained in Event binding on dynamically created elements?
$("someSelector").on("click", ".Button", function() {
...
});
You can use a delegate as Barmar suggests or you could provide yourself with a new jquery object that references your new content before running the replaceWith
Something like this, maybe:
new_element = $('<div><button>Hello World</button></div');
$(element).replaceWith(new_element);
new_element.find('button').on('click', function(e) {
console.log(e);
});

jQuery Toggling next row in dynamically created table with dynamically created button

I have a jQuery dynamically created table that appends data from json file.
one of the rows of the table is a row of buttons that are appended into a row variable that is appended into the table:
var like = $("<a href='index.html'><button class='likeBtn'>like</button></a>");
var comment = $("<a href='index.html'><button class='comBtn'>comment</button></a>");
var toggle = $("<a href='index.html'><button class='togBtn'>show/hide comments</button></a>");
row3.append(like).buttonset();
row3.append(comment).buttonset();
row3.append(toggle).buttonset();
$("#table").append(row3);
now I need to toggle the row below in the table when clicking the toggle button.
this is my onclick function:
$(function(){
alert("in");
$('.togBtn').click(function() {
alert("in2");
$(this).closest('tr').toggle();
});
});
when I put alerts inside the click function I don't see them, I do see alerts from the function that holds the click function. for example- I see "in" but I don't see "in2".
and of course the row is not toggled.
commentRow is the class of the row that needs to be toggled.
I tried lots of options like-
$("#table").closest('.commentRow').toggle();
also with next() , All(), and many others and I can't get it to work!!!
please - your thoughts on this.
All help will be much appreciated!
It's due to the dynamically generated content, try that:
$(document).on('click','.togBtn',function(e) {
alert("in2");
$(this).closest('tr').toggle();
// or return false; // it does both preventDefault & stopPropagation.
});
This is called event delegation. This technique is only used when you have generated dynamic DOM nodes like as you are doing in your code.
So, in this case all the events were bound when page was initially loaded and the elements are generated after page load, due to that browser didn't registered any event for those elements because of unavailablity. In this case event has to be delegated to the static parent node or to the document itself because it is always available.
Syntax for event delegation using .on() method:
$(staticParent).on(event, selector, cb);
With the help of the answers posted here I found a solution that works:
$(document).on('click','.togBtn',function(e) {
alert("in2");
e.preventDefault();
$(this).parents("tr").next().slideToggle();
// or return false; // it does both preventDefault & stopPropagation.
});
Thanks all for your help!

Keep .click() function after partial data update

I'm using a table for a coordinate system, and with a function in each td element to update the field value.
[ ][ ][X][ ]
[ ][X][X][X]
[X][ ][ ][ ]
When I click an empty element, I want it to set the value to "X" in my database, by getting new partial data from my rails app (and sending GET-variables along), and then re-render the table. This works just fine using my rails app, however ONLY once. It seems like the jQuery function .click() only runs once. The function looks as following: (generated via. coffeescript)
$(document).ready(function() {
$(".field").click(function(e) {
$.get("http://localhost/dinners?ap="+$(this).attr('id'), function(data) {
$("#dinner_table").html(data);
});
});
});
This will run just fine, and once I click an element, it will render new data in the table - but only once! If I redefine the .click() function after I swap the HTML in the function, it allows me to click (and update) twice, etc.
I'm pretty sure this is a basic question, but no luck with the searches so far.
Delegate the event. By doing this you need attach the handler only once.
$(".field").click(function(e) {
Will become:
$("body").on('click', '.field', function(e) {
body can be replaced with any static parent container.
Use event delegation:
$( '#dinner_table' ).on( 'click', '.field', function () {
/* your click handler */
});
So, the click-handler is bound on the common ancestor (the TABLE element, in this case).

Javascript tr click event with newly created rows (Updating css)

I am very new to web development. I am currently using tablesorter jquery plugin to create a dynamic table, where the user can add and delete rows. I am having trouble with changing the background color of newly created rows upon clicking. It works fine with rows that are hard coded in html. Here is the relevant code:
$(document).ready(
function() {
$('table.tablesorter td').click(
function (event) {
$(this).parent('tr').toggleClass('rowclick');
$(this).parent('tr').siblings().removeClass('rowclick');
});
}
)
rowclick is a CSS class here:
table.tablesorter tbody tr.rowclick td {
background-color: #8dbdd8;
}
I have tried adding the following to my Javascript function that adds a new row:
var createClickHandler =
function(newrow) {
return function(event) {
//alert(newrow.cells[0].childNodes[0].data);
newrow.toggleClass('rowclick');
newrow.siblings().removeClass('rowclick');
};
}
row.onclick = createClickHandler(row);
The alert correctly displays the text in the first column of the row when I click the new row. However, my new rows do not respond to the CSS class. Anyone have any ideas?
I should also mention that I have updated the tablesorter before applying the clickHandler with:
$("#TASKTABLE").trigger("update");
$("#TASKTABLE").trigger("appendCache");
Delegate your clickable td elements like:
$('table.tablesorter').on('click','td', function(){
using .on() from jQuery 1.7:
As of jQuery 1.7, the .on() method provides all functionality required for attaching event >handlers. For help in converting from older jQuery event methods, see .bind(), .delegate(), >and .live(). To remove events bound with .on(), see .off(). To attach an event that runs >only once and then removes itself, see .one()
Try this:
$(newrow).toggleClass('rowclick');
$(newrow).siblings().removeClass('rowclick');

jQuery: Any way to "refresh" event handlers?

I have two divs, one that holds some stuff and the other with all possible stuff. Clicking on one of the divs will transfer items to the other div. The code I came up with is:
$("#holder > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#bucket").append(this);
});
});
$("#bucket > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#holder").append(this);
});
});
This one works perfectly, except that the event handlers need to be refreshed once I append or remove elements. What I mean is, if I first click on an element, it gets added to the other div, but if I click on this element again, nothing happens. I can do this manually but is there a better way to achieve this?
Try jquery live events .. the $.live(eventname, function) will bind to any current elements that match as well as elements added to the Dom in the future by javascript manipulation.
example:
$("#holder > *").live("click", function(e) {
$(this).remove();
$("#bucket").append(this);
});
$("#bucket > *").live("click", function(e) {
$(this).remove();
$("#holder").append(this);
});
Important:
Note that $.live has since been stripped from jQuery (1.9 onwards) and that you should instead use $.on.
I suggest that you refer to this answer for an updated example.
First, live is deprecated. Second, refreshing isn't what you want. You just need to attach the click handler to the right source, in this case: the document.
When you do
$(document).on('click', <id or class of element>, <function>);
the click handler is attached to the document. When the page is loaded, the click handler is attached to a specific instance of an element. When the page is reloaded, that specific instance is gone so the handler isn't going to register any clicks. But the page remains so attach the click handler to the document. Simple and easy.
Here you go, using the more intuitive delegate API:
var holder = $('#holder'),
bucket = $('#bucket');
holder.delegate('*', 'click', function(e) {
$(this).remove();
bucket.append(this);
});
bucket.delegate('*', 'click', function(e) {
$(this).remove();
holder.append(this);
});
EDIT: don't use live, it be deprecated!
Take advantage of the fact that events bubble. Using .on():
var = function( el1, el2 ) {
var things = $('#holder, #bucket');
things.each(function( index ) {
// for every click on or in this element
things.eq(index).on('click', '> *', function() {
// append will remove the element
// Number( !0 ) => 1, Number( !1 ) => 0
things.eq( Number(!index) ).append( this );
});
});
any click on any element (existing at the time of bind or not) will bubble up (assuming you haven't manually captured the event and stopped propagation). Thus, you can use that event delegation to bind only two events, one on each container. Every click that passed the selector test of the 2nd argument (in this case, > *, will remove that element and then append it to the alternate container as accesesed by things.eq( Number(!index) )
Have you looked at jQuery's live function?
The most Efficient way (dont load all event for all elements) it:
//NORMAL FUNCTION
function myfunction_click(){
//custom action
}
$('id_or_class_of_element').on('click', myfunction_click);
//LOAD OR REFRESH EVENT
$(document).on('click', 'id_or_class_of_element', myfunction_click);

Categories