JavaScript generated elements not functioning - jQuery - javascript

I have a table as below;
<table id="mytable">
<tr>
<td>cola1</td>
<td>cola2</td>
<td>cola3</td>
<td class="rem">cola4</td>
</tr>
<tr>
<td>colb1</td>
<td>colb2</td>
<td>colb3</td>
<td class="rem">colb4</td>
</tr>
</table>
<button id="but">Add Row</button>
A button <button id="but">mybutton</button> is placed at bottom of table, which on click, adds a new row to the table. The last column of rows have class rem, which has a function to remove the parent row on click.
Here is the javascript
$(document).ready(function() {
$('#but').click(function() {
row = $("<tr></tr>");
col1 = $('<td>colex1</td>');
col2 = $('<td>colex2</td>');
col3 = $('<td>colex3</td>');
col4 = $('<td class="rem">colex4</td>');
row.append(col1,col2,col3,col4).prependTo("#mytable");
});
$('.rem').click(function() {
var $button = $(this);
var $row = $button.closest('tr');
$row.fadeOut('slow');
});
});
The function work well in above two rows. But remove button is not working in rows added by jQuery. How can I make the Javascript added rows work like others?
Here is the fiddle.

You need to use a delegated event handler, using on(), if you want it to apply to newly created elements. The way this works is by adding the handler to an element that already (and continues) to exist in the DOM, then in the handler, as the event bubbles up, it checks whether the event target matches the selector supplied to the on() function. If so, then it runs the handler otherwise it doesn't.
$('#mytable').on('click','.rem',function() {
var $button = $(this);
var $row = $button.closest('tr');
$row.fadeOut('slow');
});

I think a lot of it comes down to how you handle the functionality. You could use $.on() or some other listener, but I don't think it's necessary if you know when you're adding the element and it's entirely under your control.
For instance:
EDIT - Fixed having the click handler on the row, put it on the .rem element instead.
$(document).ready(function() {
var $row = $("<tr>"),
$col1 = $('<td>colex1</td>'),
$col2 = $('<td>colex2</td>'),
$col3 = $('<td>colex3</td>'),
$col4 = $('<td class="rem">colex4</td>');
var addrow = function() {
$row.clone(true).prependTo("#mytable");
};
var removerow = function() {
var $button = $(this),
$row = $button.closest('tr');
$row.fadeOut('slow');
};
$row.append($col1, $col2, $col3, $col4);
// This could be $($col4).click(removerow);, too.
$row.find('.rem').click(removerow);
$('#but').click(addrow);
$('.rem').click(removerow);
});
http://jsfiddle.net/sM2R8/4/
Now this uses caching of the new $row with a $.clone(true) to copy the click handlers that have been added. If you want to change the values, you'll need to clone and then update those values, but that's just a nuance to how you want to handle this. You could, also, just add the removerow handler to the cloned element before/after you append it to the table, too.

Try this:
$('#mytable').on('click', '.rem', function() {
var $button =$(this);
// ...
});
By doing that, you establish a handler on the table itself that listens for events bubbling up from contained elements. The second argument is a selector against which the actual target element is tested. If it matches (in this case, if it's a "remove" button), then your handler function is called.
Thus you can add as many rows as you like, and each new button's events will be intercepted by the same handler.

Your click handler works on existing rows only because they do exist when you call it. For future elements not in the DOM though you need to use a delegation method that accounts for both current and future elements. To do this use on() delegated to the table ( or element further up that will always exist) and add the button class as selector
$('#mytable').on('click','.rem',function() {
var $button = $(this);
var $row = $button.closest('tr');
$row.fadeOut('slow');
});

You can use
.live(event, handler)
In this case event handler will be attached to the future elements also.
so use:
$('.rem').live('click', function() {
var $button = $(this);
var $row = $button.closest('tr');
$row.fadeOut('slow');
});
However as of jQuery 1.7 live() is deprecated, use on()

Related

Which selector will be used when $(this) is called from an event with multiple elements?

I have multiple selectors in a function with onclick event. And I want to update a global variable based on whichever one is clicked.
var sort = '';
$('#firstName, #lastName, #age, #yearLevel, #gender, #event, #year').onclick(function () {
sort = $(this).attr('id');
});
Will the $(this) use the value of the id which was clicked or all of them?
Question 2:
The ids are for <a>, can I use value attribute in <a>, instead of just getting the id name?
Use click instead of onclick.
var sort = '';
$('#firstName, #lastName, #age, #yearLevel, #gender, #event, #year').click(function ()
{
sort = $(this).attr('id');
});
See Plunker: http://plnkr.co/edit/4mEvS5UE7smOpMFw?open=lib%2Fscript.js

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 dynamic element selector

I know this question has been answered a lot, but when I applied this solution Event binding on dynamically created elements? the selector selects all the elements and retrieved only the first element
$('body').on('click','a.delete',function() {
var id = $('a.delete').attr('id');
var par = $('a.delete').closest('.foo');
console.log(id);
par.hide();
postDelete(id);
});
.foo is a parent element of a.delete
this code hides all elements with class .foo and delete the first element with class a.delete not the clicked one
How can I retrieve the ID of the element I clicked and hide its parent?
You should use this instead of a.delete in click event to get the reference of clicked a.delete like following.
$('body').on('click', 'a.delete', function () {
var id = $(this).attr('id'); //change here
var par = $(this).closest('.foo'); //change here
console.log(id);
par.hide();
postDelete(id);
})
Use this to get the clicked element.
From the docs, In addition to the event object, the event handling function also has access to the DOM element that the handler was bound to via the keyword this
$('body').on('click', 'a.delete', function() {
var id = $(this).attr('id');
var par = $(this).closest('.foo');
console.log(id);
par.hide();
postDelete(id);
});

By JQuery, how to specify on function as onClick handler for many radio buttons?

I have a function called handleOnClickRadio(i, j); and lots of radio buttons named as id="something-radio[i][j]". All these radio buttons are in a table called "bigtable".
How could I attach the function handleOnClickRadio() to all these radio buttons? And call it correct with handleOnClickRadio(i,j).
Thanks.
I would not attach the click handler to the buttons at all. You say you have lots of them. Attaching the same event handler to each of them is a waste of memory and could even be a performance problem.
Use event delegation instead:
$('#tableID').delegate('input[type=radio]', 'click', function() {
// code here
});
Then you could extract the i and j via regular expression (you could also consider to change the pattern so that you can use something simpler like split()):
var exp = new RegExp("\\[(.+?)\\]\\[(.+?)\\]", 'g');
var match = exp.exec(this.id);
var i = match[1];
var j = match[2];
You could put this together like so:
$('#tableID').delegate('input[type=radio]', 'click', function() {
var match = this.id.match(/\[(.+?)\]\[(.+?)\]/)
var i = match[1]; // use parseInt(match[1]) if you need an integer
var j = match[2];
handleOnClickRadio(i,j);
});
edit: Made code a bit simpler.
If i and j correspond to column and row indicies, see #Caspar Kleijne's answer for an alternative way to retrieve them.
For accessibility, you should consider binding the handler to the change event. Then changes via the keyboard will be recognized too.
wire up the event like this
$("#bigtable input[type='radio']").bind("click", OnClickRadio);
and use the handler like
var OnClickRadio = function () {
var col = $(this).parent("td").index();
var row = $(this).parent("td").parent("tr").index();
handleOnClickRadio(col, row)
});
You can attach an onClick method to a collection of radio buttons within a table with a simple bit of jQuery. When you say 'table called "bigtable"', I'm assuming that you mean that it has id="bigtable" in the following code.
$(document).ready(function() {
$("#bigtable input:radio").click(function() {
// Your on click code here
});
});
However, I would usually give each of the radio buttons a specific class using class="magicRadioButton" and then your jQuery code becomes a little clearer and doesn't rely on all of those radio buttons being within a table;
$(document).ready(function() {
$(".magicRadioButton").click(function() {
// Your on click code here
});
});
Now, if you need to then plug this information into your current handleOnClickRadio method, you can do so with the following.
$(document).ready(function() {
$("#bigtable input:radio").click(function() {
var button_id = $(this).attr("id");
var re = new RegExp("\\[(.*?)\\]\\[(.*)\\]");
var matches = re.exec(button_id);
var i = matches[1];
var j = matches[2];
handleOnClickRadio(i,j);
});
});
Give them class names in conjunction with $(this) in your click trigger
I suggest using delegate if you have lot of radios: that way, only one Event listener will be attached
see http://api.jquery.com/delegate/
$("#globalContainer").delegate("input", "click", function(){
//Perform a string test / regex to test if the id matches something-radio[i][j]
//With a regex with capturing groups you can retrieve [i] and [j] values at the same time
if ( test($(this).attr("id")) ) {
}
});
Ideally, you'd have a onclick assigned to the big table rather than each and every radio button. Events in JavaScript bubble up so the table (which is the eventual parent of all these radio buttons) will receiving the event.
So in jQuery you would have code like this
$('#bigtable').click(handleOnClickRadio);
The signature of your handleOnClickRadio function would be
function handleOnClickRadio(evt) {
var radio = evt.target;
var id = $(radio).attr('id');
}
evt.target will identify the actual radio button that was clicked/checked and you can access other attributes of the radio as well. such as
$(radio).attr('id)
Will give you the id of the radio button.
<input type="radio" class="many-radio-buttons" ....
jQuery:
$('.many-radio-buttons').click(function() {
//your_code;
});

Is there an easier way to reference the source element for an event?

I'm new to the whole JavaScript and jQuery coding but I'm currently doing this is my HTML:
<a id="tog_table0"
href="javascript:toggle_table('#tog_table0', '#hideable_table0');">show</a>
And then I have some slightly ponderous code to tweak the element:
function toggle_table(button_id, table_id) {
// Find the elements we need
var table = $(table_id);
var button = $(button_id);
// Toggle the table
table.slideToggle("slow", function () {
if ($(this).is(":hidden"))
{
button.text("show");
} else {
button.text("hide");
}
});
}
I'm mainly wondering if there is a neater way to reference the source element rather than having to pass two IDs down to my function?
Use 'this' inside the event. Typically in jQuery this refers to the element that invoked the handler.
Also try and avoid inline script event handlers in tags. it is better to hook those events up in document ready.
NB The code below assumes the element invoking the handler (the link) is inside the table so it can traverse to it using closest. This may not be the case and you may need to use one of the other traversing options depending on your markup.
$(function(){
$('#tog_table0').click( toggle_table )
});
function toggle_table() {
//this refers to the element clicked
var $el = $(this);
// get the table - assuming the element is inside the table
var $table = $el.closest('table');
// Toggle the table
$table.slideToggle("slow", function () {
$el.is(":hidden") ? $el.text("show") : $el.text("hide");
}
}
You can do this:
show
and change your javascript to this:
$('a.tableHider').click(function() {
var table = $(this.name); // this refers to the link which was clicked
var button = $(this);
table.slideToggle("slow", function() {
if ($(this).is(':hidden')) { // this refers to the element being animated
button.html('show');
}
else {
button.html('hide');
}
});
return false;
});
edit: changed script to use the name attribute and added a return false to the click handler.
I'm sure this doesn't answer your question, but there's a nifty plugin for expanding table rows, might be useful to check it out:
http://www.jankoatwarpspeed.com/post/2009/07/20/Expand-table-rows-with-jQuery-jExpand-plugin.aspx

Categories

Resources