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")
});
Related
I have added Elements using Jquery inside PHP after loading them from the database. Each button has two classes, one controlling the GUI and another controlling the Click for particular button. The code is as under
echo "<script type='text/javascript'>$('.main').append('<button class=b_ui b$index>Change</button>'); </script>";
Now if I check the classes from Inspect Element perspective of the browser, it shows 2 classes. But when I click on it and get class of element using this code
$('.b_ui').click(function()
{
cls = $(this).attr('class');
alert('no. '+cls);
}
It shows only first class (GUI) and not the other which I want to use for handling click.
Any help ?
Put quotes around the class attribute. <button class=\"b_ui b$index\">Change</button>
You should use "on" method:
$(document).on('click', '.b_ui', function() {
cls = $(this).attr('class');
alert('no. '+cls);
});
When adding elements dynamically to the DOM, they are not accessible by jQuery like an element which was there at page load. say you have this div:
<div id="div"></div>
and you add some content with jQuery so it now looks like this:
<div id="div"><span id="span"></span></div>
you cannot refer directly to the span using jQuery with $('span[id=span]'), you have to target a containing element then filter which contained element you want:
$('#id').on('click','span',function(){});
I'm new to jQuery and am trying to create jQuery UI buttons dynamically and them to a list. I can create one list item but no more are appended after it. What am I doing wrong?
$('#buttonList').append('<li><button>'+ username + '</button>')
.button()
.data('type', userType)
.click(function(e) { alert($(this).data('type')); })
.append('<button>Edit</button></li>');
<div>
<ul id="buttonList">
</ul>
</div>
This only creates one list item with two buttons (although the second button seems to be encased in the first one, but I can probably figure that issue out). How do I get it to create multiple list items with their own unique 'data' values (i.e. I can't do a find() on a particular button class and give it data values as all buttons would then have the same data)?
I suggest to exchange the position of what you are appending and where you are appending to. This way, you retain the appended object, and should be able to work with it as a standard jQuery selector. From your code i commented out the .button() and the .append() lines, because i'm not sure what you want to do with them. Should you need help adding those lines, just drop a comment to my answer ;)
Oh, i almost forgot: i use var i to simulate different contents for username and userType data.
A JSFiddle for you is here: http://jsfiddle.net/cRjh9/1/
Example code (html part):
<div>
<p id="addButton">add button</p>
<ul id="buttonList">
</ul>
</div>
Example code (js part):
var i = 0;
$('#addButton').on('click', function()
{
$('<li><button class="itemButton">'+ 'username' + i + '</button></li>').appendTo('#buttonList')
//.button()
.find('.itemButton')
.data('type', 'userType'+i)
.click(function(e) { alert($(this).data('type'));
})
//.append('<button>Edit</button></li>')
;
i++;
});
You need complete tags when you wrap any html in a method argument. You can't treat the DOM like a text editor and append a start tag, append some more tags and then append the end tag.
Anything insterted into the DOM has to be complete and valid html.
You are also not understanding the context of what is returned from append(). It is not the element(s) within the arguments it is the element collection you are appending to. You are calling button() on the whole <UL>.
I suggest you get a better understanding of jQuery before trying to chain so many methods together
Just a very simplistic approach that you can modify - FIDDLE.
I haven't added the data attributes, nor the click function (I'm not really sure I like the
inline "click" functions - I generally do them in jQuery and try to figure out how to make
the code efficient. Probably not very rational, but I'm often so).
JS
var names = ['Washington', 'Adams', 'Jefferson', 'Lincoln', 'Roosevelt'];
for( r=0; r < names.length; r++ )
{
$('#buttonList').append('<li><button>'+ names[r] + '</button></li>');
}
$('#buttonList').append('<li><button>Edit</button></li>');
I am generating twitter bootstrap modals dynamically based on the user action (Long Story). Lets say some times user can see 100 modals on his screen. In each and every modal I have 5 dynamic buttons, each have it own purpose and did same in all modals, and have different id's.
I am attaching onClick events to those buttons by using jquery when ever there is a new twitter modal opens up by using the button id as follows
$(document).on("click","#btn"+btnNumber, function(){
//Code Goes Gere
});
So If I open 100 modals, each have 5 buttons, Is it good idea to assigning click events for 500 times ?
or Is it good Idea to assign click events by using it's name attribute for 1 time as follows
$(document).ready(function(){
$(document).on("click","btnNameAttr", function(){
//Code Goes Gere
});
});
The jQuery on() can help you in this. First you need to detach appending DATA to your element ID like btn+btnNumber. You can add your custom information in any data-x attribute like data-custom-info and use the jQuery attr('data-custom-info') syntax to retrieve the information. The event handlers registered with on() method is also available for future elements(elements created after script execution). Like below.
When creating new button, add render it as..
<input .... class="btnWithData" data-custom-info="1" ... />
<input .... class="btnWithData" data-custom-info="2" ... />
and your event handler goes like..
$(document).ready(function(){
$('body').on('click','.btnWithData',function(){
//DO WHATEVER
var buttonData=$(this).attr('data-custom-info');
//DO WHATEVER
});
});
You should assign delegated event listeners using jQuery.on() method as #Ananthan-Unni suggests, but in the form:
$.on('click', 'button', listener)
In this case you do not need to assign unique ids or attributes. You can use tag name or class name as a selector (2nd argument).
Have a look here: https://api.jquery.com/on/ and read on delegated events.
Best is don't use closures they require memory. Rely on good old data tags, instead:
$(document).ready(function () {
$("#wrapper").on("click", "btnNameAttr", function () {
var n;
n = $(this).data("number");
// code goes here
});
});
To differentiate the actually clicked element inside #wrapper you use data-number attributes like this:
<div id="wrapper">
<img data-number="000" />
<img data-number="001" />
<img data-number="002" />
<img data-number="003" />
</div>
This code will perform much better and you can still have all functionality you want by using wrapping <div> elements and data-number="" attributes. And you don't interfere with class or id attributes you might already have on those elements.
You can even add the command to the tag:
<img data-number="000" data-command="edit" />
<img data-number="000" data-command="show" />
<img data-number="000" data-command="delete" />
And switch on it:
switch ($(this).data("command"))
{
case "edit":
// edit element with number n here
break;
}
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);
});
I'm not sure, how to use .click in the right way.
I looked at the manual (http://api.jquery.com/click/) but could not find the answer for my problem:
I'm generating an div structure with JS like this:
<div>
<img id='img_1' src="click.gif">
</div>
<div id='content_1'> Text</div>
Lots of those blocks are generated with the following function. At the end, each image gets an click event to change the css of the related text: click on img_1 changes css on content_1.
I try this code (simplified version):
$.each(data, function(selector,content) {
id=prepare(selector);
$('#boxDiv').append(' <div>\
<img id="img_'+id+'" src="click.gif">\
</div>\
<div id="content_'+id+'"> Text</div>');
$('#img_'+id).click(function(a) {
$('#content_'+id).css('height','100px');});
});
But this code does not work as I exacted.
Every 'img_'+id Element gets his related click event (so far, so god)
But the function does not change the css of the related 'content_'+id! All the time, the last content element is changed.
It looks like, that the .click call-back function does not get the idat the time of adding click event, but at the time of execution the callback function. At this time, the id is (of course) always the last element.
So the question is, how to bring the current (related) id inside the .click -callback function?
//Update: I'm not sure, if using live() could help in this case: i tried this, without any success.
The problem is not an missing click event. The Problem is, that at every click, the callback-function is fired by using the last id.
Example.
The generated content looks like this:
<div>
<img id='img_1' src="click.gif">
</div>
<div id='content_1'> Text</div>
<div>
<img id='img_2' src="click.gif">
</div>
<div id='content_2'> Text</div>
<div>
<img id='img_3' src="click.gif">
</div>
<div id='content_3'> Text</div>
The JS code binds one click event to img_1, one click event to img_2 and one click event to img_3.
I changed the content of the callback function to:
$('#expand_'+id).live('click',function() {console.info(id);});
SO i see the content of ID: by clicking img_1 or img_2 id is 3. Probably because, 3 is the last value for the each loop. So how can i get the related id inside the call-back?
Thank you for any kind of help.
Found the problem in your fiddle (and your updated code):
You forgot to put varin front of id, which makes it global. All event handlers reference the same id and its value is the one from the last iteration.
Declare it as
var id = ....;
to make it local.
That said, I would use jQuery to create all the elements:
$.each(data, function(selector,content) {
var id = selector;
var $img = $('<span />', {
id: 'img_' + id,
text: 'click'
}).click(function() {
$('#content_'+id).css('height','100px');
});
var $div = $('<div />', {
id: 'content_' + id,
text: 'Text'
});
$('<div />').append($img).append($div).appendTo('#boxDiv');
});
There are also other ways to find the #content_X elements. In your structure, this element is always the next sibling of the parent of the image. So instead searching for the element with this ID, inside the event handler, you could do:
$(this).parent().next().css(...);
Or even bind the event handler to the parent div instead directly to the image.
The click event handler will have access to the id (and content) variable, as it's defined in the parent function. In JavaScript, inner functions have access to all the variables of the function in which they are defined.
The problem is simply that you are missing the # ID selector from a couple of your jQuery selector string:
$('#boxDiv').append('...');
//some code removed
$('#content_' + id).css('height', '100px');
Instead of using the .click call-back function, you should use the .live call-back function. Quoting the jquery docs:
"Description: Attach a handler to the event for all elements which match the current selector, now and in the future."
Try this:
$.each(data, function(id,content) {
$('boxDiv').append(' <div>\
<img id="img_'+id+'" src="click.gif">\
</div>\
<div id="content_'+id+'"> Text</div>');
$('#img_'+id).live('click', function() {
$('content_'+id).css('height','100px');});
});
Don't you mean
$.each(data, function(id,content) {
$('#boxDiv').append(' <div>\
<img id="img_'+id+'" src="click.gif">\
</div>\
<div id="content_'+id+'"> Text</div>');
$('#img_'+id).click, function(a) {
$('#content_'+id).css('height','100px');
});
});
? There were two missing # before ID