In the application that I'm currently creating, I am doing several AJAX calls to the server and replacing parts of my page with partial views. Everything seems to be working right except for my buttons which are "replaced" using the jQuery replaceWith() function.
In my actual code, I'm replacing a whole <div> not just a button, but the code found here will help illustrated my issue.
When the button is clicked, the JavaScript is called and thusly, that button is then updated. However, try to click on that button again, the same JavaScript will NOT be called or executed. There is some disconnect here that I'm missing. (In my mind, every time that the button with a class of "updateButton" is clicked, the javascript should be executed.) Please help me out.
Thanks
Event delegation.
$(document).on('click','.updateButton',function (e) {
e.preventDefault();
var now = new Date().getTime();
var newButton = "<span class='btn btn-info updateButton'>Update Button " + now + "</span>"
$(this).replaceWith(newButton);
});
Demo: http://jsfiddle.net/D2RLR/896/
Instead of binding the event to the button which will be removed (thus losing the event binding), bind it to an element that doesn't get removed but is an ancestor of that button.
Instead of binding the event handler on the document (as in Kevin B's answer), just re-bind it to the new button you've created to replace the old button with. This is a more efficient method of event handling because the event doesn't need to bubble all the way up the DOM tree to the document before the event fires.
http://jsfiddle.net/D2RLR/900/
var replaceBtn = function(domBtn,e) {
e.preventDefault();
var now = new Date().getTime();
var newButton = $("<span class='btn btn-info updateButton'>Update Button " + now + "</span>");
newButton.on('click',function(event) {
replaceBtn(this,event);
});
$(domBtn).replaceWith(newButton);
}
$('.updateButton').click(function(event) {
replaceBtn(this,event)
});
Related
I am creating a link tag (anchor tag) dynamically using javascript.
There is a javascript function which will be fired by an event and it will create a javascript link.
I have already mentioned the required attributes for the newly created anchor tag using javascript. Now I have also mentioned an onclick event on that anchor tag.
The problem is
that the onclick event is fired during the anchor tag creation. And it is firing for that one time. Next time when I am clicking on the link, I am unable to get my desired result.
javascript code:
function waybill()
{
var mail_link = document.createElement("a");
mail_link.href = "javascript:void(0)";
mail_link.className = 'animated bounceInDown';
mail_link.innerHTML = "Mail Waybill";
mail_link.onclick = abc_test();
var holder_div = document.getElementById("holder");
holder_div.appendChild(mail_link);
}
function abc_test()
{
alert("mail link clicked");
}
I am getting the alert only once and without even clicking.
Please help me.
mail_link.onclick = abc_test() will invoke abc_test and assign its return value to mail_link.onclick.
If you just want to reference the function, and not call it, leave out the ():
mail_link.onclick = abc_test;
Adding event listeners is one of those things that a lot of old browsers are doing in their own way, and it's a bit messy to add support for all of them. Sicnce the question is tagged jQuery, you could do all of this in jQuery and have browser support handled for you:
$('<a/>', {
href: 'javascript:void(0);',
'class': 'animated bounceInDown',
text: 'Mail Waybill',
}).appendTo('#holder').click(abc_test);
The problem is that calling abc_test() will execute the function while using only abc_test will pass a reference to the function. in this case you need to change the line:
mail_link.onclick = abc_test();
with the line:
mail_link.onclick = abc_test;
It's because that you've invoked the function instead of referencing it.
mail_link.onclick=abc_test(); - This will invoke the function while initializing
mail_link.onclick=abc_test; - This will add a reference of the function to onClick, so that it will invoke the function while you click the anchor link.
I am using datatables and fetching the data from an ajax URL. Each row of my returned table data includes a field that renders a button that looks like this:
<button type="button" data-catid="8" data-catname="Programming:JavaScript"></button>
The values assigned data-catid and data-catname come from the datatables retrieved data.
In certain cases, when the table finishes loading, I want to trigger a click on one of these buttons. My code for that is this:
$('#mydatatable').find('button[data-catid="9"]').trigger('click');
However, I cannot find a way to do this so that it occurs after the table has rendered and the button exists in the dom so I can find it and trigger the click.
I have tried drawCallback and initComplete but neither of those is triggered after the button has actually been added to the dom, allowing me to find it with jquery.
Is there a way I can do this? i.e. trigger my click after the mytable has finished retrieving its data via ajax and rendered it?
I am using datatables v 1.10
EDIT:
Here is how my click event handler is attached to the summary table.
var selectedCat = 0;
$('#mydatatable :button').click(function () {
selectedCat = this.getAttribute("data-catId");
console.log("selecteCat is " + selectedCat);
qDetailTable.ajax.url('/datatables/question-data/' + selectedCat).load();
var selectedCatName = this.getAttribute("data-catName");
$('#questDetailCat').text('Questions about: ' + selectedCatName);
$('#questSummary').hide();
$('#questDetail').show();
});
Move the click handler into a separate function, for example:
var selectedCat = 0;
function OnCategoryClick(btn){
selectedCat = btn.getAttribute("data-catId");
console.log("selecteCat is " + selectedCat);
qDetailTable.ajax.url('/datatables/question-data/' + selectedCat).load();
var selectedCatName = btn.getAttribute("data-catName");
$('#questDetailCat').text('Questions about: ' + selectedCatName);
$('#questSummary').hide();
$('#questDetail').show();
});
Event handler needs to be in a named function because you will not be able to trigger click event for elements that are not in DOM as with jQuery DataTables.
Change how you attach your click handler.
$('#mydatatable').on('click', 'button', function () {
OnCategoryClick(this);
});
Remember to always use delegated event handlers with elements inside jQuery DataTables because elements for pages other than first will not be available in DOM. See jQuery DataTables – Why click event handler does not work for more details.
Use $() API method to locate required button and call your handler function OnCategoryClick().
var btn = $('#datatable-summary').DataTable().$('button[data-catid="9"]').get(0);
OnCategoryClick(btn);
Replace datatable-summary with your actual ID of the summary table.
If you need to update details as soon as the summary table is initialized and drawn, use initComplete option to define a callback and do it there.
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");
};
I am trying to prevent a click form bubbling to the parent <a> HTML tag. Here is my code:
var $result = $("<a href='" + result["link"] + "' class='list-group-item'></a>");
var $title = $("<h4 class='list-group-item-heading'>" + result['title'] + "</h4>");
var $snippet = $("<p class='list-group-item-text'>" + result['htmlSnippet'] + "</p>");
// some code omitted for brevity
var $expandBooksbutton = $("<button type='button' id='btn-showMoreBooks' class='btn btn-default btn-xs'><span class='glyphicon glyphicon-resize-full'></span> expand</div></button>");
$expandBooksbutton.on('click', function(event){
event.stopPropagation();
var height = $('#book-container').height();
if(height != 200){
$('#book-container').height(200);
}
else{
$('#book-container').height(100);
}
});
I am wrapping the whole thing in the anchor tag <a> because I am crafting a search result item.
Regardless of adding event.stopPropogation(); the click event on the <a> still fires.
You can try this
$(<a tag selector>).on('click',function(e){
e.preventDefault();
});
There is a difference between preventing bubbling and cancelling out the default browser behaviour. Try adding
return false;
in the end of your handler function, like this
$expandBooksbutton.on('click', function(event){
var height = $('#book-container').height();
if(height != 200){
$('#book-container').height(200);
}
else{
$('#book-container').height(100);
}
return false;
});
This should be the solution if I understood the question correctly.
UPDATE
Sorry, I should have mentioned that there's also an alternative for this (which actually I should have given as an advice primarily) and this is:
event.preventDefault();
This function actually prevents the default behaviour, whereas
return false;
does both (stops bubbling & prevents default behaviour)
There's more info on this here:
event.preventDefault() vs. return false
Without knowing your full DOM structure, this will be slightly abstract. However event handlers bound to an element before it is added to the DOM aren't actually triggered.
From the jQuery docs:
Event handlers are bound only to the currently selected elements; they
must exist on the page at the time your code makes the call to .on().
To ensure the elements are present and can be selected, perform event
binding inside a document ready handler for elements that are in the
HTML markup on the page. If new HTML is being injected into the page...attach event handlers after the new HTML is placed into the page. Or, use delegated events....
So basically you have two options:
Create a handler for a delegated event and bind that to the parent element after the parent is added to the DOM. Note that this approach requires that the parent be nested inside the <a> as well.
$(parent-elem).on('click', '#btn-showMoreBooks', function(e) {
// your handler logic
});
Of course, you can always keep your logic as-is, but bind the handler to the element only after it's added to the DOM. This is reasonable as long as you won't be re-creating that element dynamically more than once after the initial page load.
So basically I want to after clicking button add div with contacts and after clicking any of contacts alert info. Its just to simulate Loading of contacts from xmpp server and after loading opening new tab for chat.
HTML:<button>append</button>
JQuery:
$("button").on("click", function(){
$("body").append("<div id='kontakty'><ul><li id='test3-imserver-soc'><div class='roster-kontakt offline'><div class='roster-meno'>test3</div><div class='roster-jid'>test3#imserver.soc</div></div></li><li id='test-imserver-soc'><div class='roster-kontakt offline'><div class='roster-meno'>test</div><div class='roster-jid'>test#imserver.soc</div></div></li></ul></div>");
});
so far everything works fine and contacts are appended to body, but when i try to execute:
$("#kontakty").on("click", ".roster-kontakt", function(){
var jid = $(this).find(".roster-jid").text();
var meno = $(this).find(".roster-meno").text();
alert(meno + "\n" + jid);
});
its not working, but if I try to execute 2nd function on contacts I want to append used as body of site (without appending) its working fine. Any idea why this happens?
Change your second event to use body and not the id.
id="kontakty" doesn't exist yet when the event is created and therefore doesn't fire. Attach higher in the DOM to avoid this problem.
$("body").on("click", ".roster-kontakt", function(){
var jid = $(this).find(".roster-jid").text();
var meno = $(this).find(".roster-meno").text();
alert(meno + "\n" + jid);
});
The second problem that you have is that when you click the "button" that the first event is bound to, you'll create the same batch of HTML with duplicate ID's. ID's have to be unique, so you'll need to use classes instead.
$("button").on("click", function(){
$("body").append("<div class='kontakty'><ul><li class='test3-imserver-soc'><div class='roster-kontakt offline'><div class='roster-meno'>test3</div><div class='roster-jid'>test3#imserver.soc</div></div></li><li class='test-imserver-soc'><div class='roster-kontakt offline'><div class='roster-meno'>test</div><div class='roster-jid'>test#imserver.soc</div></div></li></ul></div>");
});
Updated <div id='kontakty'> to <div class='kontakty'>
Updated <li id='test3-imserver-soc'> to <li class='test3-imserver-soc'>
Updated <li id='test-imserver-soc'> to <li class='test-imserver-soc'>
With the delegated event listener bound to the body, that code won't have to change.