JQuery: adding event handler (animation) on dynamically created element - javascript

I need to get a dynamically created list item within unordered list to simultaneously be animated while being created.
My JQuery code setup:
$("button#enterAction").click(function(){
var userAction = $('input#action').val();
$("ul.list-group").append('<li class="list-group-item" id="added-list-item">'+userAction+'</li>');
});
Now this code above creates a list item without animation to it. How do I add animation (say .toggle or .animate) to only this list item without affecting my whole unordered list?
I thought it could be achieved by firing a second event on dynamically created element with an ID added-list-item but I am not sure how to correctly write it down (syntax and functions used). Please help.

You can add a hidden element and then fade it out:
$("ul.list-group").append('<li class="list-group-item" style="display:none">'+userAction+'</li>').children(':last').fadeIn();
Working example:
$(function() {
$("button#enterAction").click(function(){
var userAction = $('input#action').val();
$("ul.list-group").append('<li class="list-group-item" style="display:none">'+userAction+'</li>').children(':last').fadeIn();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="action">
<button id="enterAction">Add</button>
<ul class="list-group"></ul>

There are two ways of binding events Direct and Delegated. You are using the direct method which applies on existing elements only. To let event listener work on dynamic elements you'll need to use the second method.
Direct method: $(selector).click(callback);
Delegated method: $(selector).on('click', callback);
Delegated method will work for you.

you could bind click to your new created item.
here is an example
$("button#enterAction").click(function(){
var userAction = $('input#action').val();
var li = $('<li class="list-group-item" id="added-list-item">'+userAction+'</li>'); // create li
li.bind("click", function(){
/// code goes here
})
$("ul.list-group").append(li);
});

Related

How to create an event listener using JQuery?

I am new to JQuery. I know this question is a little bit confusing but, maybe this explanation might help:
I have a dynamic <li> tag generated by JavaScript with dynamic Id's, I just want to add an event listener to every new generated <li> tag. Maybe in a way like this ? I know this doesn't work.
<li id="2" onadded="createEvent()"></li> //new generated <li> tag
<li id="1" onadded="createEvent()"></li> //the 1st generated <li> tag
<script>
function createEvent(){
//event here
}
</script>
How can I achieved that ? or any possible solution? Thanks in advance.
Using $.fn.on function to bind event for parent of li , and use selector "li" for li, then your dynamic generated li elment will reponse the event. Like following:
//$(document) can be replaced by $(parentsOfLi) , .i.e: $("ul") or $("#" + idOful)
$(document).on("click", "li", function () {
//do your process here
//alert($(this).text());
//$(this).parent().append("<li></li>")
})

Applying an onclick event to an element that doesn't exist on page load

I have styled a list to look like a select box and I want to fire a function when the user clicks an element in the list however the element is loaded via AJAX and hence isn't there when the page loads and I can't bind an onclick event to it onDomReady.
If I had it as a normal select list I could just tag on an onChange event to the <select> field, but I obviously can't do that in my case.
My HTML:
<div id="main_category_field" class="fields">
<div class="cat_list">
<ul>
<li class=""><a rel="1866" href="#1866">Sports Cards ></a></li>
<li class=""><a rel="1867" href="#1867">Gaming Cards ></a></li>
<li class=""><a rel="1868" href="#1868">Non-Sport Cards ></a></li>
<li class=""><a rel="1869" href="#1869">Supplies & Storage ></a></li>
<li class=""><a rel="1940" href="#1940">Video Games </a></li>
</ul>
</div>
<div class="contentClear"></div>
</div>
How can I run a function whenever the user clicks any of these options? Also would be great if you could also advise how to pass the respective value of the rel back when they click an option.
Using jQuery so options in that would be preferred.
Edit: Meant to say that the main element main_category_field is a static element. The elements inside are loaded via AJAX.
you need to delegate your elements to static parent , if the element is added dynamically using on()
try this
$(document).on('click','li a',function(e){
e.preventDefault();
var rel = this.rel;
//or using attr()
var rel=$(this).attr('rel');
alert(rel);
});
however delegating it to its closest static parent(present at a time of insertion) is better than document itself.. so if you are adding the list inside main_category_field div.. then you can use
$('#main_category_field').on('click','li a',function(e){
//same stuff
The key word is event delegation. If you want to assign event handlers to dynamically added elements for which you know their "future" selectors, you should use the .on() method on an (already existing) parent element of those dynamic elements.
The second parameter to .on() is then the selector of the dynamically added elements
$(document).on('click', '.cat_list li a', function(e) {
alert(this.rel); // show the "rel" attribute of the clicked a element
e.preventDefault(); // to prevent the default action of anchor elements
});
To bind an event handler to an element that does not yet exist on the page use on.
$(document).on("click", "#main_category_field", function(e){
e.preventDefault();
var rel = e.target.rel;
});
JS Fiddle: http://jsfiddle.net/82bAb/
Use .on for listen dynamically created dom elements as follows
$(document).on('click','div.cat_list ul li a',function(){
var rel=$(this).attr('rel');//to get value of rel attribute
alert(rel);
//other operations
});

When a Div class is clicked, alert it's inner content's Div Class

How do i even put these, let me try. In the following sets of codes, i want to click 'parentclass' and have an alert value of 'child1' and when i click the class below it which is 'Parent 2' have an alert fire with a value of 'child2'
So this must alert the content of that class only and not the entire class.
Here's some Javascript in Jquery.
var childclass = $('.childclass').html();
$('.parentclass').click(function(e) {
alert (childclass)
});
$('.childclass').click(function(e) {
e.stopPropagation()
e.preventDefault()
});
And HTML
<a href="" onClick="return false">
<div class='parentclass'>
Parent 1
<div style="display:none" class="childclass">child1</div>
</div>
</a>
<a href="" onClick="return false">
<div class='parentclass'>
Parent 2
<div style="display:none" class="childclass">child2</div>
</div>
</a>
This line var childclass = $('.childclass').html(); doesnt make sense as it doesn't know which element in particular you mean. The result of that will just be child1child2 which is just a concatenation of the .html() of all the elements with class childclass. This is obviously not what you want.
Therefore you should dynamically find the child with a class of childclass upon receiving the click event.
$('.parentclass').click(function(e) {
alert($(this).find('.childclass').html())
});
Also, you should know that your child class event handler is useless as we don't care if the event gets propogated downwards. If you DID care, then your e.stopPropagation() and e.preventDefault() should be in the event handler of the parent class.
You need to fetch the html of the clicked parent element within the click handler
$('.parentclass').click(function (e) {
alert($(this).find('.childclass').html())
});
$('.childclass').click(function (e) {
e.stopPropagation()
e.preventDefault()
});
Demo: Fiddle
Several ways you can go about this.
First, if your HTML will not be dynamic (elements already exist when page loads), then you can select elements by the parent class name and assign click event as so:
$('.parentclass').click(function(e) {
// the first variable here is selecting the inner elements having class 'childclass'
// keep in mind, if more than one child having that class is present within this parent, it will select all of them
var child = $(this).find('.childclass');
// here we alert the text of the inner child found
// if it is more than one, you will have undesired results. you may want to specify `.first()`
alert(child.text())
})
For newer jQuery you can also use $('.parentclass').on('click', function(e) {.
If you expect any pieces of parentclass to be dynamic, then you'll want to delegate the event based on either a static parent to the parents or document. This can be like so:
$(document).on('click', '.parentclass', function(e) {
alert($(this).find('.childclass').text())
})
Or, if you have a static (already there when page loads) wrapping element, give it an ID like `parentClassWrapper' and assign the click event dynamically as:
$('#parentClassWrapper').on('click', '.parentclass', function(e) {
alert($(this).find('.childclass').text())
})
Some helpful links:
jQuery API
jQuery Selectors
.click()
.on()
Some info on Event Delegation
jquery on vs click methods
jQuery .on('click') vs. .click() and .delegate('click')
jquery .live('click') vs .click()
I made several adjustments to your html that are worth noting. There's no need for the <a> tag. Don't use inline js - onlick in your html. Note that I wrapped the text inside of the div in the <a> tag instead. This markup is more semantic. Also, move your styles to css rather than in the html.
<div class="parent">
<a>Parent 1</a>
<a class="child">child of parent 1 contents</a>
</div>
<div class="parent">
<a>Parent 2</a>
<a class="child">child of parent 2 contents</a>
</div>
css:
.parent > .child { /* good practice: only select an immediate child of the parent */
display: none;
}
The other answers here are using find() to select the child, but I recommend children() instead. For example, if you had additional nested .childs, find() will select them all, but children() will only select direct .childs of the parent, so it is better in this case. I also recommend using the console for debugging rather than alert.
Live demo here (click).
$('.parent').click(function() {
var $child = $(this).children('.child');
var cls = $child.attr('class');
console.log(cls);
$child.show(); //added so that you can click the child
});
$('.child').click(function() {
var html = $(this).html();
console.log(html);
//if you just want the text, use this instead:
var text = $(this).text();
console.log(text);
});

Dynamic ID / Dynamic Functions / Jquery Dialogs

I have the following html, dynamically created.
<a class="open"></a>
<div class="dialog"></div>
<a class="open"></a>
<div class="dialog"></div>
<a class="open"></a>
<div class="dialog"></div>
<a class="open"></a>
<div class="dialog"></div>
Using the follwing jquery, I'm assigning ID's to each a aswell as each div
$('a.open').prop('id', function(i){
return '' + (i + 1);
});
$('div.dialog').prop('id', function(i){
return 'dialog' + (i + 1);
});
I'm then using the assigned ID's to trigger a jquery ui Dialog pop-up, however, I'm having to rewrite the function below for x number of times. Is there a way to create the below function so I do not have to rewrite it x number of times. (x being the max. number of times the the divs may appear on page).
$("#1").click(function(){
$("#dialog1").dialog("open");
});
Sounds like an ideal use for data attributes. When you dynamically generate the <a> tags, assign them a data attribute like so:
<a class="open" data-openNumber="1"></a>
(You can also do this via jQuery, of course).
Then all you have to do is write a single click handler:
$('body').on( 'click', '.open', function(){
var num = $(this).data('openNumber');
$('#dialog'+num).dialog( 'open' );
});
Note that I don't attach the handler directly to elements with class open; if I did that, I would have to do it every time the elements were dynamically created. Instead, I attach the handler to the body, and filter it by class open; that way I don't have to keep re-declaring that click handler. If you have a more handy enclosing class, you can use that instead of body, but not knowing your page structure, I didn't know what that element would be, so I just used body.
I made a jsFiddle to demonstrate the concept. I hope it's helpful:
http://jsfiddle.net/Jammerwoch/Z9U67/
What about this?
HTML
<a class"open" data-id="1">open</a>
<div class="dialog" data-id="1"></div>
JS
$(document).on("click", ".open", function(e) {
var id = $(this).data("id");
$(".dialog[data-id="+ id +"]").dialog("open");
});
If you are only using the id attribute to listen for clicks later on. It makes more sense to create a single event listener for the group.
$("a.open").on("click", function(){
$(this).find(".dialog").dialog("open")
});

jQuery .on() not firing event handler

Scenario
I have a list of users, within each list item is a <header> and a <div> wrapper - they are siblings:
<li class="user">
<header>
// ...
</header>
<div class="user-wrapper">
// ...
</div>
</li>
I am toggling the div wrapper when the user header is clicked.
What currently works:
// the handler is called
$('li.user > header').live('click', function () {
$(this).next('.user-wrapper').toggle();
});
As live() has been deprecated and I am using jQuery 1.7.2, I want to use on().
What does not work:
// Direct style
$('li.user > header').on('click', function () {
$(this).next('.user-wrapper').toggle();
});
// Delegated style
$('li.user').on('click', 'header', function () {
$(this).next('.user-wrapper').toggle();
});
In either on() scenario, the anonymous handler function is not being called.
Question
First... why is on() choking?
Second... if/when it works, using the delegate style, can i still reference the header's sibling div in the same manner as above?
[EDITED]
For delegate event handling the syntax of .on() is:
// 'element' must be static and an ancestor to 'target'.
$(element).on(eventName, target, handlerFunction);
Your delegate scenario above should work, assuming your li.user tags are static at the time of binding.
$('li.user').on('click', 'header', function () {
$(this).next('.user-wrapper').toggle();
});
If you test this in jsFiddle, it works as is. It seems like your li.user elements are being created dynamically.
If li.user is dynamically created then use a different (static) parent selector. If your list ul is always present, for example:
// HTML
<ul class="user-list">
<li class="user">
<header>
// ...
</header>
<div class="user-wrapper">
// ...
</div>
</li>
</ul>
// JavaScript
$('ul.user-list').on('click', 'li.user > header', function() {
$(this).next('.user-wrapper').toggle();
});
Thanks
Lots of gratitude to #thecodeparadox - his answer explains the issue best and is marked as such. My answer below just explains the details of how/why the list items became dynamic.
Further explanation
Knockout.js is being used to template the li elements. This alone was not the issue as the li elements were created before the .on() bindings occurred and are still treated as "static".
The killer was a ko.computed() property on the knockout model. The property reloads the collection here/there. From the moment the collection is reloaded, the scaffolding of the li items is redone and all the .on() break.

Categories