How to detect clicks on generated elements? - javascript

I'm making a group of elements from a JSON data:
Example:
{
'name':'form',
'elements':[
{'name':'bt1','type':'button','value':'hello','order':'1'},
{'name':'img1','type':'image','value':'http://www.images.com/img.jpg','order':'2'}]
}
What i do with this json is create a form with the elements described in 'elements' with a code like this:
(I've got this draft in mumbo jumbo + jquery code)
$('#container').html();//clears the container
for each element in elements do
switch element.type
case 'button':
$('#container').append('<input type="submit" value="'+element.value + ... etc');
end case
case 'image':
insert image bla bla bla
end switch
end for each
I want to detect if an element gets clicked or another kind of action, like mouse hover, etc. How do i bind this to the elements?
Also, how do i update the elements without destroying them?
EDIT: I implied something important, my bad:
I need to link the data in the elements javascript object with the generated html elements. A data field wich i retrieve when an action is triggered. That's the porpouse of all this.

You have two options. You can bind the listeners after you've created the elements, like this:
var $input = $('<input type="submit" value="'+element.value + ... etc')
.focus(...).blur(...).etc.;
$('#container').append($input);
Or, you can use event delegation. On your initial page load you can do this:
$("#container").on( "focus", "input", function(){...});
This will cover all input elements in #container either currently or dynamically added later. You can read more about event delegation in the on docs.

Building the form is really very easy, since you've basically mapped all of the attributes of the elements in an object sytanx. As such, we can create these elements with nothing more than choosing a tag, and passing the attribute object in as the second parameter of the jQuery function:
/* Container reference, counting variable */
var container = $("#container"), i = 0;
/* Clear out the container */
container.html("");
/* Cycle through each element */
while ( current = data.elements[i++] ) {
/* Evaluate the value of the current type */
switch ( current.type ) {
/* Since <input type='button|image'> are so similar, we fall-through */
case "button":
case "image" :
/* Choose a base element, pass in object of properties, and append */
$("<input>", current).appendTo(container);
break;
}
}
When it comes to registering clicks, or any other type of event, we'll use the $.on method. Because we're passing in a selector ( "input" in this case ), this will not only match all present elements, but all future elements as well.
/* Listen for all clicks on input elements within the container */
container.on("click", "input", function(){
/* We have a button, and an image. Alert either the value or src */
alert( this.value || this.src );
});
Online Demo: http://jsbin.com/izimut/edit#javascript,html

To detect events on dynamically added elements, you should use on() for jQuery 1.7+ and .live() for previous versions.
EDIT: And yes, as James pointed out in the comments, delegate() is always recommended over live().

if your js code is short, just add your js code in the append function.
append('<input type="submit" onclick="xxxx" value="'+element.value + ... etc');
if your js code is long, you can add an id to your new element.
and add event to the id.
$("#idxx").click(function(){alert("Hello");});

Either bind the element directly
$input = $('<input type="submit" value="'+element.value + ... etc');
$input.on('click', function() {
// do something
}
$('#container').append($input);
or put the bind on a parent that checks the select of what was click inside..
$('#container').on('click', 'input', function() {
// do something
}

Related

jQuery selector precedence when using pattern matching

I am creating a form that implements a bunch of similar elements. They are custom select boxes, created out of <ul>s.
Some of these elements are slightly different in the way I want the mousedown event to be handled though.
The way I have it set up currently is that, by appending _custom_select to the end of an elements class name, it will be treated as one of these special elements as far as CSS is concerned.
However, when the string selections is found inside a class name (that will coincidentally also end with _custom_select in order to apply the proper styling) I want to use a different mousedown event handler.
This is the relevant section of my event listener set up:
$('[class$="_custom_select"] li').mousedown(function(event){
var opt= event.target;
if(opt.className!='li_disabled' && event.which==1)
{
if(opt.className=='li_unselected'){
opt.className= 'li_selected';
}
else{
opt.className= 'li_unselected';
}
update_selections(opt.parentElement);
}
});
$('[class*="selections"]').mousedown(function(event){
var opt=event.target;
if(event.which==1){
if(opt.className=='li_unselected'){
opt.className= 'li_selected_2';
}
else{
opt.className= 'li_unselected';
}
}
});
This code works, but notice how, in the second binding, I had to bind the event listener to the ul that holds the li that is actually being clicked.(The ul is the element whose class name matches the pattern) In the first one however, I can bind the event listener directly to the li elements contained within the ul.
If I change the second jQuery selector to $('[class*="selections"] li') the event listener is never bound to the corresponding lis.
What is causing this behavior?
I am aware that I can just check event.target.tagName to ensure the event is bubbling up from an <li>, but that is not what the question is about.
I originally thought it had something to do with precedence and that the listeners weren't being bound because the lis that would have matched the second selector already matched against the first selector.
However, after implementing logging and looking at the DOM I have determined that when I change the second selector to: $('[class*="selections"] li') neither event listener is bound to the lis that match the second selector.
Here is a link to a JS fiddle of the 'working version'. If you add ' li' to the second selector and then try to click the <li>s in the box to the right, you will see that they no longer become green.
jsFiddle
https://jsfiddle.net/6sg6z33u/4/
Okay, thanks for posting the jsFiddle. This is an easy fix!
The elements in your second li are being added dynamically. When you bind to elements using the shortcut methods like .click() it only binds to the elements on the page when it initially bound
The fix: use the .on() method, which is the preferred method per jQuery foundation. This method allows for live binding meaning it will pick up on dynamic elements.
$('[class*="selections"]').on( 'mousedown', 'li', function(event) {
var opt = event.target;
if (event.which == 1) {
if (opt.className == 'li_unselected') {
opt.className = 'li_selected_2';
} else {
opt.className = 'li_unselected';
}
}
});

Assign java scripts to cloned HTML element

I have a html div and I clone it using Jquery. That div contains labels and text fields. ids of all of them generated and assigned dynamically. I have no problem with that.
A java script is assigned to a text field of original div. The cloned text fields does not have the javascript assigned to it.
the script I need to assign:
<script>
$(function() {
$("#datepick_onBooking,#datepick_Pay1,#datepick_Pay2,#datepick_totPay,#datepick_deedFees").datepicker();
});
</script>
the script I use to make clones:
<script>
var i = 3;
//When DOM loaded we attach click event to button
$(document).ready(function() {
$('#addAnotherPayment').click(function() {
var cloned = $('.PayDiv0').first().clone();
var noOfDivs = $('.PayDiv0').length+2;
cloned.insertBefore("#totPayForm");
// append count to the ids
cloned.attr('id', 'PayDiv' + noOfDivs);
cloned.find('label').attr('id', 'PayLbl' + noOfDivs);
cloned.find('input[type="text"]').attr('id', 'datepick_Pay'+ noOfDivs);
cloned.find('input[type="number"]').attr('id', 'amount_Pay'+ noOfDivs);
cloned.find('.PayLbl2').html("Payment No " + i++ + ':');
});
});
</script>
datepick_Pay1, datepick_Pay2, datepick_totPay, datepick_deedFees are static elements and they have been assigned to the script. I create text fields using cloning as datepick_Pay3,datepick_Pay4, and so on.
I cannot figure out how to dynamically assign the script to that newly created elements.How can I do that?
A Boolean indicating whether event handlers and data should be copied along with the elements.
change this line.
var cloned = $('.PayDiv0').first().clone(true);
when you clone something especially elements which having events
use parameter as
clone(true)
But this will be harmfull based on how event is attached on the actual element when copying the events to the cloned element may affect the actual.
You need to clone with events. http://api.jquery.com/clone/
var cloned = $('.PayDiv0').first().clone(true);
Then your script needs to be changed to work for dynamic elements. Here as soon as input elements gets focus, asssign the datepicker based on wild card id selector, if it doesn't already have one.
$(function() {
$('body').on('focus',"input[id^=datepick_]", function(){
if(!$(this).hasClass('.hasdatepicker'))
{
$(this).datepicker();
}
});
});

Dynamically adding onchange function to drop down with jQuery

I have a couple of drop down boxes with ids country1, country2, ... When the country is changed in a drop down the value of the country shoudl be displayed in an alert box.
if I add the onchange handler for one box like this it works fine:
$('#country1') .live('change', function(e){
var selectedCountry = e.target.options[e.target.selectedIndex].value;
alert(selectedCountry);
});
But I need to do this dynamically for all drop down boxes so I tried:
$(document).ready(function() {
$('[id^=country]') .each(function(key,element){
$(this).live('change', function(e){
var selectedCountry = e.target.options[e.target.selectedIndex].value;
alert(selectedCountry);
});
});
});
This doesn't work. No syntax error but just nothing happens when the seleted country is changed. I am sure that the each loop is performed a couple of times and the array contains the select boxes.
Any idea on that?
Thanks,
Paul
The reason .live() existed was to account for elements not present when you call the selector.
$('[id^=country]') .each(function(key,element){ iterates over elements that have an id that starts with country, but only those that exist when you run the selector. It won't work for elements that you create after you call .each(), so using .live() wouldn't do you much good.
Use the new style event delegation syntax with that selector and it should work:
$(document).on('change', '[id^=country]', function(e) {
// ...
});
Replace document with the closest parent that doesn't get dynamically generated.
Also, consider adding a class to those elements along with the id attribute.
Instead of incremental ids I'd use a class. Then the live method is deprecated but you may use on with delegation on the closest static parent or on document otherwise.
$('#closestStaticParent').on('change', '.country', function() {
// this applies to all current and future .country elements
});
You don't need an each loop this way; plus events are attached to all the elements in the jQuery collection, in this case all .country elements.

Jquery get id or class from dynamic element

Let say I have 5 element from PHP query (so it is dynamic)
Illustrated below:
element 1 class=element id=id_1
element 2 class=element id=id_2
element 3 class=element id=id_3
element 4 class=element id=id_4
element 5 class=element id=id_5
We ussulay use jquery event by knowing their class or id, but in this case, we don't know exactly their id.
$("#id_3").click(function()
{
//in this case we have known we want to add event when we click id_3
});
How to deal with dynamic element from PHP query?
For example, how can we know that we click on element 3 with id_3?
What must we fill in $(????).click();?
When I use class, how can I know which id I reference from the class clicked?
This was the only way I could get it to work. For example, if you wanted to get the attribute ID or the value of the element that has been clicked...
$("containerElem").on("click", "someElemID", function(evt) {
var getElemID = $(evt.target).attr("id");
var getVal = $(evt.target).val();
});
In your example the elements all have the same class, so you can setup your event handler based on that:
$(".element").click(function() {
// "this" refers to the clicked element
// this.id will be the id of the clicked element
});
Or if these elements are dynamic in the sense of being loaded via Ajax at some point after the initial page load use a delegated event handler:
$("somecontainerelement").on("click", ".element", function() {
// do something with this.id
});
Where "somecontainerelement" would ideally be the element that the dynamic elements are added to, but could just be document.
If they all have the same class, then you can use a class selector. Then use this to find whatever property you are after.
$('.element').click(
$(this).prop('id');
);
If you want to add a click only then why not add that to the generated html on server side?
You can use attribute starsWith selector & on to bind events on dynamically created elements.
$('body').on('click', '[id^=id]', function(e){
});
This is veryusefull when we work on unknown elements with id or class
$( document ).ready(function() {
// user this if element is div
$('div[id^="id_"]').on('click', function() {
alert($(this).attr('id'));
});
// user this if element is input
$('input[id^="id_"]').on('click', function() {
alert(this.id);
});
});

Javascript/jQuery - How do I obtain name of the class of clicked element?

I googled and googled and I concluded that it's very hard to get answer on my own.
I am trying to use jquery or JavaScript to get a property of clicked element. I can use "this.hash" for example - it returns hash value I presume.
Now I would like to get name of the class of clicked element.
Is it even possible? How? And where would I find this kind of information?
jQuery documentation? - All I can find is methods and plugins, no properties.. if its there - please provide me with link.
JavaScript documentation? - is there even one comprehensive one? again please a link.
DOM documentation? - the one on W3C or where (link appreciated).
And what is this.hash? - DOM JavaScript or jQuery?
In jQuery, if you attach a click event to all <div> tags (for example), you can get it's class like this:
Example: http://jsfiddle.net/wpNST/
$('div').click(function() {
var theClass = this.className; // "this" is the element clicked
alert( theClass );
});
This uses jQuery's .click(fn) method to assign the handler, but access the className property directly from the DOM element that was clicked, which is represented by this.
There are jQuery methods that do this as well, like .attr().
Example: http://jsfiddle.net/wpNST/1/
$('div').click(function() {
var theClass = $(this).attr('class');
alert( theClass );
});
Here I wrapped the DOM element with a jQuery object so that it can use the methods made available by jQuery. The .attr() method here gets the class that was set.
This example will work on every element in the page. I'd recommend using console.log(event) and poking around at what it dumps into your console with Firebug/Developer tools.
jQuery
​$(window).click(function(e) {
console.log(e); // then e.srcElement.className has the class
});​​​​
Javascript
window.onclick = function(e) {
console.log(e); // then e.srcElement.className has the class
}​
Try it out
http://jsfiddle.net/M2Wvp/
Edit
For clarification, you don't have to log console for the e.srcElement.className to have the class, hopefully that doesn't confuse anyone. It's meant to show that within the function, that will have the class name.
$(document).click(function(e){
var clickElement = e.target; // get the dom element clicked.
var elementClassName = e.target.className; // get the classname of the element clicked
});
this supports on clicking anywhere of the page. if the element you clicked doesn't have a class name, it will return null or empty string.
$('#ele').click(function() {
alert($(this).attr('class'));
});
And here are all of the attribute functions.
http://api.jquery.com/category/attributes/
You can use element.className.split(/\s+/); to get you an array of class names, remember elements can have more than one class.
Then you can iterate all of them and find the one you want.
window.onclick = function(e) {
var classList = e.srcElement.className.split(/\s+/);
for (i = 0; i < classList.length; i++) {
if (classList[i] === 'someClass') {
//do something
}
}
}
jQuery does not really help you here but if you must
$(document).click(function(){
var classList =$(this).attr('class').split(/\s+/);
$.each( classList, function(index, item){
if (item==='someClass') {
//do something
}
});
});
There's a way to do this without coding. Just open the console of your browser (f12?) and go to element you want. After that, hover or click the item you want to track.
Every change done on the DOM will be for a few seconds marked (or lightened) as another color on the console. (Watch the screen capture)
On the example, each time I hover a "colorItem", the 'div' parent and the "colorItem" class appears lightened. So in this case the clicked class will be 'swiper-model-watch' or 'swiper-container' (class of the lightened div)

Categories