Reputation: 5024
I'm dynamically creating a list using JQuery and would like to bind each element to a "tap" event. How would I do this? Here is a sample of what I'm trying to do, but it isn't working.
for(var i=1; i <= 5; i++) {
var id = "item" + i;
var li = $("<li data-theme=\"d\" id=\"" + id + "\">Item " + i + "</li>");
li.appendTo(ul);
$(document).delegate("#"+id, "tap", function() {
$("#"+id).attr({ "data-theme" : "e", "class" : "ui-li ui-li-static ui-btn-up-e" });
});
}
This code triggers when tapping any element, however it always modifies the last element in the list for some reason.
Upvotes: 0
Views: 333
Reputation: 11381
YOUR OPTIONS
Either move the event handling to outside the loop
for(var i=1; i <= 5; i++) {
....
}
$(document).delegate("[id^=item]", "tap", function() {
});
Use the bind
method and apply the tap
event to the element, and not to the document
.
for(var i=1; i <= 5; i++) {
//append li to ul
$("#"+id).bind("tap", function() {
$(this).attr({
"data-theme" : "e",
"class" : "ui-li ui-li-static ui-btn-up-e"
});
});
}
BUT, the best way to be to put the event
outside the loop, and bind the event to ul
which will later delegate it to li.
for(var i=1; i <= 5; i++) {
....
}
$("ul").delegate("[id^=item]", "tap", function() {
});
NOTE
If you want to change your theme, you also need to update your layout once.
$("ul").delegate("[id^=item]", "tap", function() {
$(this).attr({
"data-theme" : "e",
"class" : "ui-li ui-li-static ui-btn-up-e"
}).parent("ul").listview().listview("refresh");
});
USE OF STARTS WITH
SELECTOR
You've put this in your code :
var id = "item" + i;
That means for the whole loop of 5 elements, your ids are gonna look like this :
<li id="item1">..
<li id="item2">..
<li id="item3">..
<li id="item4">..
Looking at the common thing here, I'd say it is :
item
So, since your ids start with item
you could generalise it by using the starts with selector. So,
id^=item
means that you're searching for elements with id that starts with item
. And since its an attribute,
[id^=item]
A MORE MODULAR APPROACH
This method involves lesser HTML :
//your ul tag
var ul = $("ul")
//set up an array for adding li to it.
var li = [];
//a temporary element to store "li"
var $li;
for(var i=1; i <= 5; i++) {
//add required attributes to the element
var $li = $("<li/>", {
"data-theme" : "d",
"id" : "item" + i,
"html" : "Item " + i
});
//push that into array
li.push($li);
}
//wait for append to finish
ul.append(li).promise().done(function () {
//wait for list to be added - thats why you wait for done() event in promise()
//add the click events to this - event delegation - this way your click event is added only once
$(this).on("tap", "[id^=item]", function () {
$(this).attr({
"data-theme" : "e",
"class" : "ui-li ui-li-static ui-btn-up-e"
}).parent("ul").listview().listview("refresh");
});
//then refresh
$(this).listview().listview("refresh");
});
Here's a demo for this : http://jsfiddle.net/hungerpain/TdHXL/
Hope this helps!
Upvotes: 3
Reputation: 276596
Here is what I'd do:
var items = []; // an actual JavaScript array - a list of items.
for(var i=1;i<=5;i++){
items.push({theme:'d'}); //add an item to our list,
//Anything that actually relates to the item should be
//here, text, other data and such. This is our 'view model'.
}
items.forEach(function(item,i){ // for each item, bind to the dom
var el = document.createElement("li"); //create an element
el.textContent = i+1; // set its text
el.onclick = function(e){ // or ontap or whatever
el.className = "ui-li ui-li-static ui-btn-up-e";
item.theme = "d";
}//you mind want to use addEventListener instead at a later point
item.el = el;
ul.appendChild(el); // you need access to ul, currently being a jQuery object ul[0].
});
Note we have access to the items directly from our code, we can update them directly and such and have a direct reference to them. We don't need to query our own data - we own it and know directly how to get to it.
Also - we don't have a 80kb dependency. No complex selectors, no 'magic' bindings. Everything is straight forward and it's just plain ol' javascript.
Note: forEach should be shimmed (easily) for older browsers.
Upvotes: 1
Reputation: 55750
Just move the event handler to outside the for loop.
And replace
$(document).delegate("#"+id, "tap", function() {
with
$(document).delegate("[id*=item], "tap", function() {
JS
for (var i = 1; i <= 5; i++) {
var id = "item" + i;
var li = $("<li data-theme=\"d\" id=\"" + id + "\">Item " + i + "</li>");
li.appendTo(ul);
}
$(document).delegate("[id*=item]", "tap", function () {
$("#" + id).attr({
"data-theme": "e",
"class": "ui-li ui-li-static ui-btn-up-e"
});
});
Upvotes: 1