$(function() {
$.getJSON("companies.json", function(response) {
var html = '<table id="tbl">';
response.businesses.forEach(function(row) {
html += '<tr><td>' + row.id + '</td><td>' + row.name;
});
html += '</table>';
$("#tabledata").html(html);
});
$(".move").click(function() {
var $id = $(this).attr("idname");
$.getJSON("companies.json", function(response) {
$.map(response.businesses, function(obj) {
if (obj.id == $id)
console.log(obj);
return obj; // or return obj.name, whatever.
});
});
});
});
HTML:
<div id="tabledata" class='left'></div>
<div class="right"></div>
Please help?
As your .move element is added to your page dynamically, you have to make use of jQuery's on() method to delegate the event to an ancestor of the .move element which does exist when your JavaScript first loads.
$(document).on('click', '.move', function() { ... });
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.
You can read more about jQuery's event delegation here.
If you use event delegation, your problem goes away (and your app becomes more performant and less prone to memory leaks).
// Only do this once, when your page loads...
$(document.body).on('click', '.move', function (ev) {
// This is the link that was clicked.
var $targ = $(ev.target);
});
Try This
$('#tabledata').on('click', '.move', function(e) { ... });
The reason the event isn't being triggered is because the event is only added to elements that exist on the page when you call the .click() method.
Instead, you can use event delegation:
$(document.body).on('click', '.move', function (ev) {
var $targ = $(ev.target);
});
which really says: call the function when any element that matches .move that's inside document.body is clicked.
I know others have said this already but I wanted to make event delegation clearer.
Related
$(".btn").click(function()
{
$(".content").append(
"<div class='randomDiv' id='1'></div>"
);
}
If above is "active" then I cannot:
$(".randomDiv").click(function()
{
alert($(this.attr("id")));
}
I've googled and found out that it is because JS is loaded before I append, but haven't found a solution how to "register after load" on JS.
Either:
Attach the event handler when you create the element
$(".btn").click(function() {
$("<div class='randomDiv' id='1'></div>")
.on("click", myFunction)
.appendTo(".content");
}
function myFunction() {
alert($(this.attr("id")));
}
… so the element does exist when you bind the event handler
Use a delegated handler
$(document).on("click", ".randomDiv", function () {
alert($(this.attr("id")));
});
… that captures all the click events as they bubble up the document and checks which elements they came from.
$(".content").on('click', '.randomDiv', function()
{
alert($(this.attr("id")));
}
$(".content") can be replaced with any existing parent item of randomDiv. Say content div is inside page-left div then above code can be written as
$(".page-left").on('click', '.randomDiv', function()
{
alert($(this.attr("id")));
}
Or even
$(document).on('click', '.randomDiv', function()
{
alert($(this.attr("id")));
}
which bind event to the document level in DOM
Depending upon the version of jQuery you should use live, delegate, bind or on function.
If you append the element dynamically then the normal click function wont work. Use
$(document).on("click",".randomDiv",function(event){
alert($(this).attr("id"));
});
On this click event, it changes the clicked elements class from 'fa-pencil-square-o' to 'fa-floppy-o'.
$("i.fa.fa-pencil-square-o").click(function () {
var parentid = $(this).parent().attr('id');
var parent = $('tr#' + parentid);
var rtn;
var rtd;
if (parent.find('td:nth-child(4)').text() == 'No') {
rtn = parent.find('td:nth-child(2)').text();
rtd = parent.find('td:nth-child(3)').text();
parent.find('td:nth-child(2)').empty();
parent.find('td:nth-child(3)').empty();
//changes class here
parent.find('td:nth-child(5)').empty();
parent.find('td:nth-child(5)').append('<i class="fa fa-floppy-o" aria-hidden="true"></i>');
parent.find('td:nth-child(2)').append('<input type="text" id="rtName" />');
parent.find('td:nth-child(3)').append('<input type="text" id="rtDescription" />');
$(parent).find('input#rtName').val(rtn);
$(parent).find('input#rtDescription').val(rtd);
}
});
When the class of the same clicked element changes to 'fa-floppy-o' I wanted this click event to take effect but it doesn't and still invokes the first click event above.
$('.fa-floppy-o').click(function () {
var parent = $(this).parent();
var rtn = parent.find('input#rtName');
var rtd = parent.find('input#rtDescription');
$.ajax({
url: '/editRoomType',
async: false,
type: 'POST',
data: {
roomTypeID: parent.attr('id'),
roomTypeName: rtn.val(),
roomTypeDescription: rtd.val()
},
dataType: 'json',
success: function (data) {
if (data.isSuccessful) {
$('#msgdiv').css("display", "inline");
$('#msg').empty();
$('#msgdiv').removeClass('alert-danger');
$('#msgdiv').addClass('alert-success');
$.each(data.Message, function (key, value) {
$('#msg').append(value + '<br />')
})
$('.table-details tbody').empty();
parent.find('td:nth-child(5)').empty();
parent.find('td:nth-child(5)').append('<i class="fa fa-pencil-square-o" aria-hidden="true"></i>');
getRoomType();
} else {
$('#msgdiv').css("display", "inline");
$('#msg').empty();
$('#msgdiv').removeClass('alert-success');
$('#msgdiv').addClass('alert-danger');
$.each(data.Message, function (key, value) {
$('#msg').append(value + '<br />')
})
}
},
error: function () {
alert('error accounts')
}
});
});
What I basically want to accomplish is for the elements' on click event function to change when the class of the element changes. But how?
You are adding the listener directly to the element with the provided class, instead add the listener to a parent element using jQuery's on() event delegation, and provide the class of the clicked element as the second parameter. Even document works.
This is the definition of the jQuery on() event handler:
.on( events [, selector ] [, data ], handler )
Change this line:
$("i.fa.fa-pencil-square-o").click(function () {
to this:
$(document).on("click", "i.fa.fa-pencil-square-o", function() {
And this line:
$('.fa-floppy-o').click(function () {
to this:
$(document).on("click", ".fa-floppy-o", function() {
The reason being: jQuery adds those listeners once when the page loads. Because it doesn't find anything with the class .fa-floppy-o, it doesn't add a listener. This is true of renaming (re-classing) elements, and also elements dynamically generated by jQuery/Javascript after page load.
The event will bubble up from the element to the parent element and that parent element will check to see if the element has the selector provided in the second argument.
More on event bubbling:
Direct and delegated events
The majority of browser events bubble, or propagate, from the deepest,
innermost element (the event target) in the document where they occur
all the way up to the body and the document element.
...
When a selector is provided, the event handler is referred to as
delegated. The handler is not called when the event occurs directly on
the bound element, but only for descendants (inner elements) that
match the selector. jQuery bubbles the event from the event target up
to the element where the handler is attached (i.e., innermost to
outermost element) and runs the handler for any elements along that
path matching the selector.
Here's documentation for the on() function in jQuery: http://api.jquery.com/on/
I am appending item by jQuery. But after appending can't bind the event on the appended item. I am appending as follows:
var item = '<div id="'+newInputId+'" class="col-md-9" style="padding-right: 0px;">';
item += '<input id="txtInScope" type="text" value="'+currentScopeVal+'" class="form-control" readonly="readonly"/>';
item += '</div>';
item += '<div id="inScopeActionDiv'+newInputId+'" class="col-md-3" style="padding-left: 2px;">';
item += '<button type="button" class="btn btn-warning btn-sm remButton" title="Remove this item">Remove Item</button>';
item += '</div>';
$('#inScopeDiv').append(item);
And after appending this I want to bind a click event on the above remButton class as below:
$("#inScopeDiv").delegate(".remButton", "click", function(){
alert('you clicked me again!');
});
$('#inScopeDiv').on('click', '.remButton', function() {
alert("working");
})
$('.remButton').live('click', function() {
alert('live');
})
But no result. What can I try next?
$('.remButton').live('click', function() {
alert('live');
})
jquery method live is not valid anymore:
"As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live()."
Source: jquery live
Little explanation about event attachment:
You must realize that a target what you want to add a event, exists BEFORE to call the add event function(in this case with the method on of jQuery).
on another hand, exists with jquery a manner to make work a event attachment without the existence of the element before:
$('html').on('click', '#inScopeDiv .remButton', function () {
alert('works!');
});
Bind it on a parent that is not dynamic but always in the DOM.
You need to add the listener each time you add an item:
$('#inScopeDiv').append(item)
.off() //unbind old listeners so no duplicate listeners
.on('click', '.remButton', function() {
alert("working");
});
You could store the appended div in a variable using .appendTo and then you could attach the click event directly to the variable. See it working: JSFiddle
$(".appendDiv").click(function () {
var item = "<div>I'm a new div!</div>";
var appended_div = $(item).appendTo(".container");
appended_div.click(function () {
alert("Working!");
});
});
I'll try to explain my problem:
I have a website where the user dynamically adds elements. They all belong to the "toBuy" class. Whenever a new element is added to this class I need to attach a click-handler to only this element but not to all others. To keep my code clean I want to have a function that does this work. Here is what i've tried:
this is how the stuff is added:
$("#addItemButton").click(function(){
var item= $('#item').val();
$('#item').val("");
var quantity= $('#quantity').val();
$('#quantity').val("");
var comment=$('#addComment').val();
$('#addComment').val("");
//construct new html
var newitem="<div class='toBuyItem'><div class='item'>";
newitem+=item;
newitem+="</div><div class='quantity'>";
newitem+=quantity;
newitem+="</div><div class='comment'><img src='img/comment";
if(comment==""){
newitem+="_none"
}
newitem+=".png' alt='Comment'></div><div class='itemComment'>"
newitem+=comment;
newitem+="</div></div>";
$("#toBuyItems" ).prepend( newitem );
toggle("#addItemClicked");
initializeEventListeners();
});
then this is the initializeEventListeners function (which I also run when the page loads so that the existing elements have the event handlers already:
function initializeEventListeners(){
$(".toBuyItem").click(function(){
console.log($(this).html());
console.log($(this).has('.itemComment').length);
if($(this).has('.itemComment').length != 0){
console.log("toggling");
$(this).addClass("toggling");
toggle(".toggling .itemComment");
$(this).removeClass("toggling");
}
});
}
function toggle(item){
$( item ).slideToggle(500);
}
now apparently what happens is that when a new element is added the existing elements get a new event handler for clicking (so they have it twice). Meaning that they toggle on and off with just one click. Probably it's damn simple but I cannot wrap my head around it....
EDIT:
so this works:
$(document).on('click', '.toBuyItem', function(){
if($(this).has('.itemComment').length != 0){
console.log("toggling");
$(this).addClass("toggling");
toggle(".toggling .itemComment");
$(this).removeClass("toggling");
}
});
Use jquery's on method. This way you have to add event only once. This will be added automatically to dynamically added elements.
$(document/parentSelector).on('click', '.toBuyItem', function() {
// Event handler code here
});
If you are using parentSelector in the above syntax, it has to be present at the time of adding event.
Docs: https://api.jquery.com/on
You can use jQuery.on method. It can attach handlers to all existing in the DOM and created in future tags of the selector. Syntax is as follows:
$(document).on('click', '.toBuyItem', function(){
//do onClick stuff
})
As others have suggested, you can delegate click handling to document or some suitable container element, and that's probably what I would do.
But you could alternatively define a named click handler, which would be available to be attached to elements already present on page load, and (scope permitting) to elements added later.
You might choose to write ...
function buy() {
if($(this).has('.itemComment').length != 0) {
$(this).addClass("toggling");
toggle(".toggling .itemComment");
$(this).removeClass("toggling");
}
}
function initializeEventListeners() {
$(".toBuyItem").on('click', buy);
}
$("#addItemButton").on('click', function() {
var item = $('#item').val(),
quantity = $('#quantity').val(),
comment = $('#addComment').val();
$('#item', '#quantity', '#addComment').val("");
//construct and append a new item
var $newitem = $('<div class="toBuyItem"><div class="item">' + item + '</div><div class="quantity">' + quantity + '</div><div class="comment"><img alt="Comment"></div><div class="itemComment">' + comment + '</div></div>').prependTo("#toBuyItems").on('click', buy);// <<<<< here, you benefit from having named the click handler
$newitem.find(".comment img").attr('src', comment ? 'img/comment.png' : 'img/comment_none.png');
toggle("#addItemClicked");
});
Script below create button and event dynamically. I want to bind data to click event. But bind() function failed, click event just won't trigger. Anyway, click event successfully triggered if I'm using on() function.
http://jsfiddle.net/hzLv1r6s/2/
function showMessage(evt) {
alert(evt.data.message);
}
$(document).ready(function () {
var activeDiv;
var pVar = { message:'Hello from a paragraph'};
$("a").on("click", function () {
if (activeDiv === $(this).attr('id')) {
$('#__div').hide('slow');
activeDiv = '';
return;
}
$('.box1').empty();
var guts =
'<div id="__div" style="display:none;">' +
'<input type="text" id="__text" value="' + $(this).attr('data-content') + '"/><br>' +
'<button id="__internal" value="aaa">Submit</button>' +
'</div>';
//this one doesn't work on click event
$('#__internal').bind('click',pVar,showMessage);
$($.trim(guts)).appendTo('.box1');
$('#__div').show('slow');
activeDiv = ($(this).attr('id'));
});
/*
//this one does work on click event
$('.box1').on('click','#__internal',function(event){
//alert(event.target.value);
alert($('#__text').val());
});
*/
});
You need to use event delegation at this context,
$('.box1').on('click','#__internal' , showMessage);
Or try to bind the event to it after that html string got appended into the DOM.
$($.trim(guts)).appendTo('.box1');
$('#__internal').bind('click',pVar,showMessage);
NOTE: But i don't know why are you refusing to use event delegation here.
DEMO created without event delegation.