My Rails app loads links to a page dynamically. I want to append an onClick action to those links.
The links are appended to the page properly, but the JS for the page is not being applied to those newly added elements.
I've tried rendering new JS tags to the dynamically-added content. I've also tried including this block of code, which should target any link with .select-link added to the #links div.
$("#links").on("click", ".select-link", function() {
my code here...
})
That code works when the links are not dynamically loaded. However, I cannot seem to apply ANY onClick handler to them when dynamically loaded, even in the console.
What could possibly cause this issue?
For more context, the problem I'm trying to solve is here: AJAX-loaded JS not rendering
You should bind your event to document like this
$(document).on("click", "#links .select-link", function() {
my code here...
});
Try following code:
$(document).on("click", "#links .select-link", function() {
/*my code here...*/
})
or
$("#links .select-link").live("click", function() {
/*my code here...*/
})
The thing is, the code which you have in the question does work for dynamically inserted content.
The following snippet has one <div class="select-link"> which is part of the HTML and inserts two <div class="select-link"> elements via JavaScript.
jQuery is used to add two separate click handlers. The first handler is added prior to any of the dynamic content being added to the DOM. The second handler is added after the second <div class="select-link"> is added, but before the third one is inserted. Both handlers are called for all three <div class="select-link">. This demonstrates that the code you have provided in the question does work for dynamically inserted content. That means something else is going on.
$("#links").on("click", ".select-link"
,logEvent.bind(null,'#links on .select-link','jQuery'));
function logEvent(text,type,e){
var curTarget = (e.currentTarget.id)?e.currentTarget.id:e.currentTarget.nodeName;
var target = (e.target.id)?e.target.id:e.target.nodeName;
console.log(text + ' ::' + type + ' ::curTarget=' + curTarget
+ ' ::target=' + target);
}
function appendLink(id,text) {
document.querySelector('#links').insertAdjacentHTML('beforeend'
,'<div class="select-link" id="' + id + '" style="color:blue;">'
+ text + '</div>');
}
appendLink('sel-pre-ready','Selected Link 2 (added prior to document ready)');
$(document).ready(function(){
$("#links").on("click", ".select-link"
,logEvent.bind(null,'#links on .select-link','jQuery at doc ready'));
appendLink('sel-post-ready','Selected Link 3 (added after document ready)');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>Not Link</div>
<div id="links">Links
<div id="not-sel">Not Selected Link</div>
<div class="select-link" id="sel-html" style="color:blue;">Selected Link 1 (HTML)</div>
</div><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
Without more information, spending a lot of time speculating on what might be causing the problem is just wasting time.
One possibility of what is happening is that another event handler is being fired for these events and stopping propagation. One way to (mostly) check for that is to add an event handler to the window on the capture phase (i.e. not using jQuery). You could do so with the following:
//The following will catch the event prior to almost all possible
// interference by other event handlers.
window.addEventListener('click',function(e){
if(!$(e.target).is("#links .select-link")){
return; //Not one of the elements we are interested in
}//else
//e.stopPropagation();
logEvent('on window','Capture',e);
},true);
Related
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!
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.
I'm using JQUery treeview plugin to display my data as a tree structure.
The problem is I'm generating my HTML dynamically from the JSON response objects.
This never works as expected. The elements are not getting registered for click events.
If I hardcode the dynamic HTML, I'm able to see the results as expected. I debugged and understood that JQuery registers the click events for existing HTML elements, but not dynamically formed elements. Please let me know how can I register them for click events.
function show(jsonResp) {
//Parsing the JSON response and building HTML on the fly.
$red = '';
for (var i = 0; i < treeElements.length; i++) {
$red = $red + treeElements[i];
}
$("#user-records").append($red);
$("#red").treeview({
animated: "fast",
collapsed: true,
unique: true,
persist: "cookie",
toggle: function () {
window.console && console.log("%o was toggled", this);
}
});
}
This treeview code is calling the functions to expand and collapse as per the user click events. All of these events are getting registered in treeview.js
this.find("div." + CLASSES.hitarea).click( toggler );
I debugged in chrome and checked that my new div's are getting registered with the click events. But nothing is happening when I click.
P.S : If I copy the console log of the HTML element generated, and create a different page, it works perfectly. Only problem is when dynamically adding the HTML code. I'm clueless where to register the click events for this newly added dynamic HTML code.
Did you this?
$(document).on("click", ".selector", function() {
// your code
});
With this code, you can bind events on generated content. Here's an example: http://jsfiddle.net/cB8Tf/
Change this
this.find("div." + CLASSES.hitarea).click( toggler );
to this
$(document).on('click', "div." + CLASSES.hitarea, toggler);
This will cause all future instances of "div." + CLASSES.hitarea to respect the click handler you've given.
I'm generating list items that go in an unordered list. I then want to listen for a click on any of these list items. I'm aware I haven't posted the full code, but I'm hoping it isn't necessary for me to. Are elements that are appended like this completely ignored by my jQuery click function? I've tried just about everything and can't find out why! All I want to see is my "lol" alert! :(
$.each(entries, function(i, v) {
s += '<li';
if (favouriteItem(v.title)) s += ' data-theme="e"';
s += '>' + v.title + '</li>';
});
$("#linksList").append(s);
$("#linksList").listview("refresh");
$("li").click(function() {
alert("lol");
selectedEntry = $(this).data("entryid");
});
Although the items do visually appear the source code stays like this:
<div data-role="content">
<ul data-role="listview" id="linksList" data-divider-theme="b" data-inset="false"></ul>
</div>
Suggesting that there are no li elements there. Yet they do show visually? Someone please save me before I jump into a pool of lava.
Change:
$("li").click(function() {
alert("lol");
selectedEntry = $(this).data("entryid");
});
to
$('#linksList').on('click', 'li',function() {
alert("lol");
selectedEntry = $(this).data("entryid");
});
When you add elements dynamically to the document, you need to use .on()'s delegated event syntax.
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,
select the elements and attach event handlers after the new HTML is
placed into the page.
Use delegation:
$("#linksList").on('click',"li",function() {
alert("lol");
selectedEntry = $(this).data("entryid");
});