on.click not working after first click on dynamically created table - javascript

I dynamically create a table full of links of 'actors', which allows to pull the actors information into a form to delete or update the row. The delete button only pops up when you select an actor.
I'm able to click a row, pull the information into the forms, and delete it on first try. However when I attempt to add a new 'Actor' and then delete it, or just delete an existing 2nd row, the button 'Delete Actor' doesn't work. It's only after the first successful delete does the button no longer work.
var addActor = function() {
// Creates a table of links for each added actor with an id based from # of actors
$("#actorsTable").append("<tr><td><a href='' onclick='deleteActor(this)' class='update' data-idx='" + actors.length + "'>" + newActor.fName + " " + newActor.lName + "</a></td></tr> ");
$(".update").off("click");
$(".update").on("click", selectActor);
};
var deleteActor = function(e) {
$("#deleteActor").on('click', function(event) {
event.preventDefault();
var row = e.parentNode.parentNode;
row.parentNode.removeChild(row);
clearForm(actorForm);
actorState("new");
});
};
I'm new to jQuery/javascript, and I'm pretty sure its due to the change in DOM, but I just don't know what to change to make it work.
Here is an Example of it in action

Try
var deleteActor = function(e) {
$("#deleteActor").unbind();
$("#deleteActor").on('click', function(event) {
event.preventDefault();
var row = e.parentNode.parentNode;
row.parentNode.removeChild(row);
clearForm(actorForm);
actorState("new");
});
};
Here is the link for unbind.
http://api.jquery.com/unbind/

The problem is because you're adding another click handler (in jQuery) within the click handler function run from the onclick attribute. You should use one method or the other, not both. To solve the problem in the simplest way, just remove the jQuery code from the deleteActor() function:
var deleteActor = function(e) {
var row = e.parentNode.parentNode;
row.parentNode.removeChild(row);
clearForm(actorForm);
actorState("new");
};

when you add html dynamically you need to attach the event to the parent static element like so:
$("#actorsTable").on("click","a.update", function() {
$(this).closest("tr").remove();
});

Related

jQuery onChange event handler firing function twice

This is the table http://jsfiddle.net/djochw6L/1/
The event is supposed to fire when I enter value in the item column
$(document).on('change', '.item', function() {
var ite = $(this).closest('tr');
getdetails(ite);
})//event
function getdetails(dat){
var itemName = $(dat).find('.item').val();
alert (itemName);
};
The event handler works correct for the first row. But from the second row onwards it fires twice. Why is this?
The reason why it's firing twice is because your on change element fires for every class with the name item. If you look through your code you can see that on top of giving every table column the class item, you are also passing the item class to each row that is added. So the event fires twice, once for the row and once for the item column.
The code that's giving you the problem is
prot.attr("class", id + " item")
Try to fix your problem by not passing the item class to the table rows, instead of doing all kinds of hacky stuff to the event listener.
You could build your code to something along the lines of
prot.attr("class", "item-" + id)
try adding return false:
$(document).on('change', '.item', function () {
var ite = $(this).closest('tr');
getdetails(ite);
return false;
}) //event

jQuery click event lost after appenTo

I am using appendTo to move list items between two list, upon a button click. The button resides in each li element. Each li has two buttons, of which only one is visible at a time, depending on the list the li currently resides.
Here is the function:
// 'this' is the first list
// Click Handler for remove and add buttons
$(this.selector + ', ' + settings.target + ' li button').click(function(e) {
var button = $(e.target);
var listItem = button.parent('li');
listItem.children("button").toggleClass("hidden");
if (button.hasClass("assign")) {
// Add Element to assignment list
listItem.appendTo(settings.target);
}
else
if (button.hasClass("remove")) {
// Remove Element from assignment list
listItem.appendTo(source);
}
})
As long as the list item reside in the original li, the click events in the buttons are triggered. However, once it is moved to the other list using listItem.apendTo. The click item no longer fires. Why is this the case? I cant find anything about this in the docs.
Sometimes jQuery won't be able to find something if it isn't present in the DOM when your script first loads. If it is a dynamically created element, try replacing your click event handlers with 'on'
Rather than:
$(".aClass").click(function(){
// Code here
})
Try:
$("body").on("click", ".aClass", function(){
Code here
})
http://api.jquery.com/on/
You should use on event.
$(".aClass").on("click", function(){
//Your custom code
})
on event is usful for Dynamically generated data + static data already in HTML.
As recommended by user 'apsdehal', a deleate was what i needed:
// Click Handler for remove and add buttons
$(source.selector + ', ' + settings.target ).delegate("li button", "click", function(e) {
var button = $(e.target);
var listItem = button.parent('li');
listItem.children("button").toggleClass("hidden");
if (button.hasClass("assign")) {
// Add Element to assignment list
listItem.appendTo(settings.target);
}
else
if (button.hasClass("remove")) {
// Remove Element from assignment list
listItem.appendTo(source);
}
});

How to get ID of listview item Clicked. [javascript / jquery / jquery mobile]

I need advice on how to detect which <li> is tap/click by the user, then write the 'ID' of the tap/clicked <li> into Localstorage, then use the saved Localstorage to retrieve data for Detail Page.
I'm new to javascript/jquery, if you can provide some simple example code will be very much appreciated.
I know how to write Localstorage, read Localstorage, get JSON data from server API, generate Loop for Listview with unique ID for each <li>.
What I need is, how to use JS to make <li> clickable (link to Detail Page) and write to Localstorage at the same time.
I have tried:
$('.liClass').click(function() { //block of code to write Localstorage };
But the <li> is not clickable and no key/value written to Localstorage. Not to mention to detect which <li> is clicked (this I have no idea).
Please advice, thank you.
Code update:
//Show restaurant listing - NOTE: This is not first page. Link from other Page.
$('#restaurantList').on("pagebeforecreate", function() {
$.getJSON("http://mydomain.com/api/restaurant", function( data ) {
function rstListing(data) {
if ($.isEmptyObject(data) === true) {
alert ('JSON return empty');
} else {
for (i=0; i<data.length; i++){
$('#restaurantListing').append('<li id="' + data[i].restaurant_id + '" class="rstList"><img src="http://mydomain.com/file/img/' + data[i].restaurant_logo + '"><h2>' + data[i].name + '</h2><p>' + data[i].city + '</p></li>');
$('#restaurantListing').listview('refresh');
}
}
}
rstListing(data);
}
);
});
//Listview link to Detail Page
$(document).ready(function(){
$('.rstList').click(function() {
var id = $(this).attr("id"); // Get the ID
alert(id);
console.log(id);
});
});
Also tried:
//Listview link to Detail Page
$('#restaurantList').on("pageload", function() {
$('.rstList').click(function() {
var id = $(this).attr("id"); // Get the ID
alert(id);
console.log(id);
});
});
You don't need to make any <li> element to be clickable by your self, when you add the click event to any element, that will be triggered when the item is clicked.
Your problem will basically be that the element is not loaded when the event is bind to it. So you have to add your code inside document ready event like this.
$(document).ready(function(){
$('.liClass').click(function() {
var id= $(this).attr("id"); // Get the ID
};
});
$('.liclick').click(function() {
alert($(this).attr("id"));//Get id of clicked li
localStorage.setItem($(this).attr("id"),$(this).attr("id")); //stored into localStorage
alert("Data from localStorage "+localStorage.getItem($(this).attr("id"))); // get stored id
});
Working Fiddle
You will need to use the event delegation to assign the click event since you are building the HTML DOM dynamically via JSON request, thus not being able to locate the 'li' elements at the time of the page load. So, it would look like:
$(document).on("click", ".rstList", function (event) {
// click event
}
See this link for more details:
jQuery event delegation
I have solved my problem with the example code provided by stackoverflow member here. My previous problem is because I separate the creation of the listview and bind the click listener in two different page event.
After testing the page event sequence, I'm now putting the click listener into the same page event instead of separate to two. Now my code look like this, hope this will help someone bump into the same problem as me:
//Show restaurant listing
$('#restaurantList').on("pagebeforecreate", function() {
alert('pagebeforecreate event triggered');
$.getJSON("http://mydomain.com/api/restaurant", function( data ) {
function rstListing(data) {
if ($.isEmptyObject(data) === true) {
alert ('JSON return empty');
} else {
for (i=0; i<data.length; i++){
$('#restaurantListing').append('<li id="' + data[i].restaurant_id + '" class="rstList"><img src="http://mydomain.com/file/img/' + data[i].restaurant_logo + '"><h2>' + data[i].name + '</h2><p>' + data[i].city + '</p></li>');
$('#restaurantListing').listview('refresh');
}
}
}
rstListing(data);
alert('rstListing() executed');
$('.rstList').click(function() {
alert($(this).attr("id"));//Get id of clicked li
localStorage.setItem($(this).attr("id"),$(this).attr("id")); //stored into localStorage
alert("Data from localStorage "+localStorage.getItem($(this).attr("id"))); // get stored id
});
}
);
});

Table onclick rows jQuery

I've a table whose content is getting generated via an AJAX success response.
HTML code
<table class="table table-hover" id="table_content"></table>
AJAX code
$.ajax({
dataType: "json",
type : "POST",
url: "/configuration/",
data : { 'selected_item' : selected_item_id },
success : function(result){
var table_heading = "<tr>"
var table_content = ""
for (var heads in result[1]){
table_heading +="<th style='background-color:#f1f1f1;'>" + result[1][heads] + "</th>"
}
for (var region in result[0]){
table_content += "<tr>"
for (var details in result[0][region]){
table_content += "<td>" + result[0][region][details] + "</td>"
}
}
table_content = table_heading + table_content
$("#table_content").html(table_content)
},
});
I want to apply an onclick function to it. Like this:-
Onclick function code
$(function(){
$('#table_content tr').click(function () {
$('.test').slideUp(0)
$(this).append(($('.test')).slideDown('slow'));
});
});
The issue that I'm facing is that I'm not able to click the row, if I generate the content via AJAX response. If I create a table inside the HTML itself, it'll work, but not when the table is created via AJAX response.
What's the problem? Please sugggest.
EDITED
What I'm trying to achieve is that a div should be slide down just below the row upon clicking the row. I does works for the first time when the data gets generated via AJAX. but it does not works when I'm generating data after the first time, though the event is triggered but $('.test').slideUp(0) $(this).append(($('.test')).slideDown('slow')); does not works after the first time. Nor any error is popped . See http://jsfiddle.net/fVz6D/5/
Updated:
See working demo: http://jsfiddle.net/c5FgG/1/
Your problem was that you attached the test div element to a table row, which dissapeared after repopulating the table. Instead, clone the test div on each click when you are changing the table content, and use the clone instead the original.
Old answer:
Add the onclick function code inside the ajax success function. It works out for me this way:
...
$("#table_content").html(table_content);
$('#table_content tr').click(function () {
alert("Clicked");
//your code
});
...
And don't forget to close the table rows with:
table_content += "</tr>";
The way you are using click to bind the event only binds the event to elements that are present in DOM at time the binding code is executed. You need event delegation for binding event with dynamically generated html elements using on().
$(function(){
$('#table_content').on('click', 'tr', function () {
$('.test').slideUp(0)
$(this).append(($('.test')).slideDown('slow'));
});
});
Delegated events
Delegated events have the advantage that they can process events from
descendant elements that are added to the document at a later time. By
picking an element that is guaranteed to be present at the time the
delegated event handler is attached, you can use delegated events to
avoid the need to frequently attach and remove event handlers, reference.
Try
$(function(){
$('#table_content').on('click', 'tr', function () {
$('.test').slideUp(0)
$(this).append(($('.test')).slideDown('slow'));
});
});
The on() handler should work on newly created elements too.
$(function(){
$('#table_content').on('click', 'tr', function () {
$('.test').slideUp(0)
$(this).append(($('.test')).slideDown('slow'));
});
});
Here Is a list of fiddles :
fiddle1
fiddle2
fiddle3
fiddle4
You can use it as per your requirement.
Use on() for dynamically added elements like,
$('#table_content').on('click',' tr', function () {
$('.test').slideUp(0)
$(this).append(($('.test')).slideDown('slow'));
});
Updated your div will move to tr which you clicked, so when you click on list it will generate new content in table so your div.test will be removed from HTML, thats why you are not getting the desc div again.
To solve this problem you have to add div.desc again in clicking of list like,
if(!$('body > div.test').length){
$("body").append('<div class="test">You slide down a row with content xyz</div>');
}
Full code
$('#list').on('click', 'li', function () {
var id = this.id;
var table_content = "";
// IF id=1,2,3,4,5 Code
$("#table_content").html(table_content);
// add below code foe div.desc
if (!$('body > div.test').length) {
$("body").append('<div class="test">You slide down a row with content xyz</div>');
}
});
Demo
Alternatively, you can use clone() like,
$(function () {
$('#table_content').on('click', 'tr', function () {
$clone=$('.test:not(.new-test)').clone();// clone the first test class element
$('.new-test').remove();// remove the cloned elements
$clone.addClass('new-test').appendTo('body');// add the clone to body
$clone.slideUp(0);// playing with clone now
$(this).append($clone.slideDown('slow'));
});
});
Working demo

Create hidden field element for each drop

I know this is a similar question to my previous one however its slightly different.
I have this script adding each 'dropped' element to a list. Now i need it adding into a variable / hidden field so i can pass it to the next page via a form.
When i run it at the moment. It alerts for each one however, it does it not just for every item dropped but if there are 10 items dropped it will run 10 times per item droped rather than once per item dropped.
Any help would be great.
//Record and add dropped items to list
var txt = $("#listbox");
var dtstart = copiedEventObject.start + '\n'
var caltitle = copiedEventObject.title
var txt = $('#listbox');
txt.append("<li class ='listItem'> "+dtstart +"</li>")
var listItems = $('.listItem');
$('#calendarform').submit(function() {
listItems.each(function(){ //For each event do this:
alert( listItems.text() );
});
return false;
});
// remove the element from the "Draggable Events" list
$(this).remove();
the problem lies in this code
listItems.each(function(){ //For each event do this:
alert( listItems.text() );
});
you are alerting the text of all the list items for each list item.
use jQuery(this) to access the current item within an each block
listItems.each(function(){ //For each event do this:
alert( $(this).text() );
});
Assuming your code is within a drop event handler, you are also adding a submit handler each time you drop. This means that each time you drop, you queue up another submit event. This is probably not desired. Move this submit(function(){}) block outside your drop handler to prevent it from firing that function more than once.
$('#calendarform').submit(function(e) {
var listItems = $('.listItem');
listItems.each(function(){ //For each event do this:
alert( listItems.text() );
});
e.preventDefault();//stop normal behavior
return false;
});
and to create elements on the fly you just pass jQuery the html, and append it to your form.
$('<input type="hidden" name="listItem[]"/>').appendTo("#calendarForm").val(listItem.text())
you may have to fiddle with the name element to get it to submit as an array in your server side language, but you're also within an each loop, which provides you with an index, so you can do the following.
$('#calendarform').submit(function(e) {
var form = $(this);
var listItems = $('.listItem');
listItems.each(function(index){ //For each event do this:
var listItem = $(this);
$("<input type='hidden'/>").val(listItem.text()).appendTo(form).attr('name', 'listItem[' + index + ']');
});
e.preventDefault();//stop normal behavior
return false;
});

Categories

Resources