greenie2600
2008-Jul-01 00:25 UTC
Attaching event observers to a series of elements - best practice?
Hi all,
New member here. I''ve been working with Prototype for a while, and I
love it. However, there''s one thing I still can''t figure out.
Let''s say I have an array of objects, representing contacts in an
address book:
var contacts = [
{ id: 1, firstName: "Bob", lastName: "Smith" },
{ id: 2, firstName: "Sue", lastName: "Johnson" },
{ id: 3, firstName: "Tim", lastName: "Horton" }
];
I''d like to iterate over this array, create an <li> for each
contact,
and—here''s the tricky part—attach an onclick observer to each
<li>,
which calls the openContact() function and passes in the ID of the
contact that was clicked.
I understand closures. However, I haven''t found an elegant way to
solve the problem. This won''t work:
function populateContactsList( contacts )
var theUL = document.getElementById("addr-book-index");
var thisLI = null;
for ( var i = 0; i < contacts.length; i++ ) {
thisLI = document.createElement("li");
thisLI.appendChild( document.createTextNode( contacts[i].name ) );
theUL.appendChild( thisLI );
Event.observe( thisLI, "click", function() {
openContact( contacts[i].id );
} );
}
}
...because every call to openContact() will receive 3 as the parameter
- the value of contacts[i].id at the time the outer function exits.
I''ve been kludging my way around the problem by storing data in the
element''s id attribute (e.g., <li
id="contacts-index-3">Tim Horton</
li>), but I''m not entirely happy with this solution. Suggestions?
For bonus points: I like to use innerHTML to insert new content into
the DOM. Yes, it''s non-standard, but it''s widely supported,
and it''s
much faster than the DOM methods - see http://quirksmode.org/dom/innerhtml.html.
If you can suggest a clean technique that allows me to keep using
innerHTML *and* attach onclick handlers in the way I''ve described,
I''ll write a song extolling your greatness.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Spinoffs" group.
To post to this group, send email to
rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-spinoffs?hl=en
-~----------~----~----~----~------~----~------~--~---
greenie2600
2008-Jul-01 00:56 UTC
Re: Attaching event observers to a series of elements - best practice?
Hey! I found the Function.curry() method, and it works! Is this the best way? On Jun 30, 8:25 pm, greenie2600 <greenie2...-/E1597aS9LQAvxtiuMwx3w@public.gmane.org> wrote:> Hi all, > > New member here. I''ve been working with Prototype for a while, and I > love it. However, there''s one thing I still can''t figure out. > > Let''s say I have an array of objects, representing contacts in an > address book: > > var contacts = [ > { id: 1, firstName: "Bob", lastName: "Smith" }, > { id: 2, firstName: "Sue", lastName: "Johnson" }, > { id: 3, firstName: "Tim", lastName: "Horton" } > ]; > > I''d like to iterate over this array, create an <li> for each contact, > and—here''s the tricky part—attach an onclick observer to each <li>, > which calls the openContact() function and passes in the ID of the > contact that was clicked. > > I understand closures. However, I haven''t found an elegant way to > solve the problem. This won''t work: > > function populateContactsList( contacts ) > > var theUL = document.getElementById("addr-book-index"); > var thisLI = null; > > for ( var i = 0; i < contacts.length; i++ ) { > thisLI = document.createElement("li"); > > thisLI.appendChild( document.createTextNode( contacts[i].name ) ); > theUL.appendChild( thisLI ); > Event.observe( thisLI, "click", function() { > openContact( contacts[i].id ); > } ); > } > > } > > ...because every call to openContact() will receive 3 as the parameter > - the value of contacts[i].id at the time the outer function exits. > > I''ve been kludging my way around the problem by storing data in the > element''s id attribute (e.g., <li id="contacts-index-3">Tim Horton</ > li>), but I''m not entirely happy with this solution. Suggestions? > > For bonus points: I like to use innerHTML to insert new content into > the DOM. Yes, it''s non-standard, but it''s widely supported, and it''s > much faster than the DOM methods - seehttp://quirksmode.org/dom/innerhtml.html. > If you can suggest a clean technique that allows me to keep using > innerHTML *and* attach onclick handlers in the way I''ve described, > I''ll write a song extolling your greatness.--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Trevan Richins
2008-Jul-01 01:35 UTC
Re: Attaching event observers to a series of elements - best practice?
greenie2600 wrote:> Hi all, > > New member here. I''ve been working with Prototype for a while, and I > love it. However, there''s one thing I still can''t figure out. > > Let''s say I have an array of objects, representing contacts in an > address book: > > var contacts = [ > { id: 1, firstName: "Bob", lastName: "Smith" }, > { id: 2, firstName: "Sue", lastName: "Johnson" }, > { id: 3, firstName: "Tim", lastName: "Horton" } > ]; > > I''d like to iterate over this array, create an <li> for each contact, > and—here''s the tricky part—attach an onclick observer to each <li>, > which calls the openContact() function and passes in the ID of the > contact that was clicked. > > I understand closures. However, I haven''t found an elegant way to > solve the problem. This won''t work: > > function populateContactsList( contacts ) > > var theUL = document.getElementById("addr-book-index"); > var thisLI = null; > > for ( var i = 0; i < contacts.length; i++ ) { > thisLI = document.createElement("li"); > > thisLI.appendChild( document.createTextNode( contacts[i].name ) ); > theUL.appendChild( thisLI ); > Event.observe( thisLI, "click", function() { > openContact( contacts[i].id ); > } ); > } > > } > > ...because every call to openContact() will receive 3 as the parameter > - the value of contacts[i].id at the time the outer function exits. > > I''ve been kludging my way around the problem by storing data in the > element''s id attribute (e.g., <li id="contacts-index-3">Tim Horton</ > li>), but I''m not entirely happy with this solution. Suggestions? > > For bonus points: I like to use innerHTML to insert new content into > the DOM. Yes, it''s non-standard, but it''s widely supported, and it''s > much faster than the DOM methods - see http://quirksmode.org/dom/innerhtml.html. > If you can suggest a clean technique that allows me to keep using > innerHTML *and* attach onclick handlers in the way I''ve described, > I''ll write a song extolling your greatness.You could use Event Delegation and attach the onclick listener to the ul and then inside of the listener function use event.element().id to grab the id of the item that was clicked on. This way, you can build the content using innerHTML (or .update() which is basically the same thing) and only have one event listener to worry about (reduces memory footprint). --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Travis Miller
2008-Jul-01 01:39 UTC
Re: Attaching event observers to a series of elements - best practice?
Event delegation, eh? I''ve encountered the concept in passing, but I''ve never really tried it out. I can see the benefits in terms of performance, though. I''m on a roll tonight, so I''ll do some Googling, and see what I can do. Thanks! ----- Original Message ---- From: Trevan Richins <developer-P5Ep+WoDybrQT0dZR+AlfA@public.gmane.org> To: rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org Sent: Monday, June 30, 2008 9:35:00 PM Subject: [Rails-spinoffs] Re: Attaching event observers to a series of elements - best practice? greenie2600 wrote:> Hi all, > > New member here. I''ve been working with Prototype for a while, and I > love it. However, there''s one thing I still can''t figure out. > > Let''s say I have an array of objects, representing contacts in an > address book: > > var contacts = [ > { id: 1, firstName: "Bob", lastName: "Smith" }, > { id: 2, firstName: "Sue", lastName: "Johnson" }, > { id: 3, firstName: "Tim", lastName: "Horton" } > ]; > > I''d like to iterate over this array, create an <li> for each contact, > and—here''s the tricky part—attach an onclick observer to each <li>, > which calls the openContact() function and passes in the ID of the > contact that was clicked. > > I understand closures. However, I haven''t found an elegant way to > solve the problem. This won''t work: > > function populateContactsList( contacts ) > > var theUL = document.getElementById("addr-book-index"); > var thisLI = null; > > for ( var i = 0; i < contacts.length; i++ ) { > thisLI = document.createElement("li"); > > thisLI.appendChild( document.createTextNode( contacts[i].name ) ); > theUL.appendChild( thisLI ); > Event.observe( thisLI, "click", function() { > openContact( contacts[i].id ); > } ); > } > > } > > ...because every call to openContact() will receive 3 as the parameter > - the value of contacts[i].id at the time the outer function exits. > > I''ve been kludging my way around the problem by storing data in the > element''s id attribute (e.g., <li id="contacts-index-3">Tim Horton</ > li>), but I''m not entirely happy with this solution. Suggestions? > > For bonus points: I like to use innerHTML to insert new content into > the DOM. Yes, it''s non-standard, but it''s widely supported, and it''s > much faster than the DOM methods - see http://quirksmode.org/dom/innerhtml.html. > If you can suggest a clean technique that allows me to keep using > innerHTML *and* attach onclick handlers in the way I''ve described, > I''ll write a song extolling your greatness.You could use Event Delegation and attach the onclick listener to the ul and then inside of the listener function use event.element().id to grab the id of the item that was clicked on. This way, you can build the content using innerHTML (or .update() which is basically the same thing) and only have one event listener to worry about (reduces memory footprint). --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
Frederick Polgardy
2008-Jul-01 01:46 UTC
Re: Attaching event observers to a series of elements - best practice?
FYI, you don''t quite understand closures, because you don''t
have one in this
case. :-)
Your for-loop (var i = 0; i < contacts.length; i++) { ... } doesn''t
create a
closure - this just creates a block, which has no special scoping rules at
all in JS. By the time the loop finishes, you have created three distinct
closures (your event handlers, which are inner functions) - but they all
point to the same variable i, which is 3.
If you had said contacts.each(function(contact) { ... }), and then referred
to contact.id inside the function, you would have had the results you were
looking for because each iteration of the loop has its own closure.
Does that make sense?
-Fred
On Mon, Jun 30, 2008 at 7:25 PM, greenie2600
<greenie2600-/E1597aS9LQAvxtiuMwx3w@public.gmane.org> wrote:
>
> I understand closures. However, I haven''t found an elegant way to
> solve the problem. This won''t work:
>
> function populateContactsList( contacts )
>
> var theUL = document.getElementById("addr-book-index");
> var thisLI = null;
>
> for ( var i = 0; i < contacts.length; i++ ) {
> thisLI = document.createElement("li");
>
> thisLI.appendChild( document.createTextNode( contacts[i].name ) );
> theUL.appendChild( thisLI );
> Event.observe( thisLI, "click", function() {
> openContact( contacts[i].id );
> } );
> }
>
> }
>
> ...because every call to openContact() will receive 3 as the parameter
> - the value of contacts[i].id at the time the outer function exits.
--
Science answers questions; philosophy questions answers.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Spinoffs" group.
To post to this group, send email to
rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-spinoffs?hl=en
-~----------~----~----~----~------~----~------~--~---
kangax
2008-Jul-01 14:02 UTC
Re: Attaching event observers to a series of elements - best practice?
Yes, #curry is one of the options. You could also "freeze" i by
explicitly storing it in a separate closure (for each enumeration):
for ( var i = 0; i < contacts.length; i++ ) {
...
Event.observe( thisLI, "click", (function(i) {
return function(){ openContact( contacts[i].id ); }
})(i));
...
}
-- kangax
On Jun 30, 8:56 pm, greenie2600
<greenie2...-/E1597aS9LQAvxtiuMwx3w@public.gmane.org>
wrote:> Hey! I found the Function.curry() method, and it works!
>
> Is this the best way?
>
> On Jun 30, 8:25 pm, greenie2600
<greenie2...-/E1597aS9LQAvxtiuMwx3w@public.gmane.org> wrote:
>
> > Hi all,
>
> > New member here. I''ve been working with Prototype for a
while, and I
> > love it. However, there''s one thing I still can''t
figure out.
>
> > Let''s say I have an array of objects, representing contacts
in an
> > address book:
>
> > var contacts = [
> > { id: 1, firstName: "Bob", lastName: "Smith"
},
> > { id: 2, firstName: "Sue", lastName: "Johnson"
},
> > { id: 3, firstName: "Tim", lastName: "Horton"
}
> > ];
>
> > I''d like to iterate over this array, create an <li> for
each contact,
> > and—here''s the tricky part—attach an onclick observer to each
<li>,
> > which calls the openContact() function and passes in the ID of the
> > contact that was clicked.
>
> > I understand closures. However, I haven''t found an elegant
way to
> > solve the problem. This won''t work:
>
> > function populateContactsList( contacts )
>
> > var theUL = document.getElementById("addr-book-index");
> > var thisLI = null;
>
> > for ( var i = 0; i < contacts.length; i++ ) {
> > thisLI = document.createElement("li");
>
> > thisLI.appendChild( document.createTextNode( contacts[i].name ) );
> > theUL.appendChild( thisLI );
> > Event.observe( thisLI, "click", function() {
> > openContact( contacts[i].id );
> > } );
> > }
>
> > }
>
> > ...because every call to openContact() will receive 3 as the parameter
> > - the value of contacts[i].id at the time the outer function exits.
>
> > I''ve been kludging my way around the problem by storing data
in the
> > element''s id attribute (e.g., <li
id="contacts-index-3">Tim Horton</
> > li>), but I''m not entirely happy with this solution.
Suggestions?
>
> > For bonus points: I like to use innerHTML to insert new content into
> > the DOM. Yes, it''s non-standard, but it''s widely
supported, and it''s
> > much faster than the DOM methods -
seehttp://quirksmode.org/dom/innerhtml.html.
> > If you can suggest a clean technique that allows me to keep using
> > innerHTML *and* attach onclick handlers in the way I''ve
described,
> > I''ll write a song extolling your greatness.
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Ruby on Rails: Spinoffs" group.
To post to this group, send email to
rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
To unsubscribe from this group, send email to
rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org
For more options, visit this group at
http://groups.google.com/group/rubyonrails-spinoffs?hl=en
-~----------~----~----~----~------~----~------~--~---