Gotcha with Prototype.Bind and Arrays
If the title sounds confusing, that is because it is. I couldn't figure out a better way to describe the issue I was running into. Let see if I can better demonstrate. I have a "initialize" function defined in my JavaScript object as such:
initialize: function() {
// siteID contains a list of ids such as "1,2,3,4"
// Convert the id list in siteIDs to a prototype array
// ($A(siteIDs)) and for each element in the array,
// run a function passing it the single siteID
$A(siteIDs).each(function(siteID) {
// If an element exists on the page with the id of
// setCurrentSiteElementPrefix + current siteID
if ($(this.setCurrentSiteElementPrefix + siteID)) {
// Add an observer to the 'click' event of that
// element and bind it to the 'getContent' function
$(this.setCurrentSiteElementPrefix + siteID).observe(
'click',
this.getContent.bind(this)
);
}
});
}
where "siteIDs" is a comma delimited list of ids ("1,2,3,4") and "setCurrentSiteElementPrefix" is a part of the name of link element with a dynamically generated id (such as setCurrentSiteElementPrefix_1, setCurrentSiteElementPrefix_2). Here is the above loop in pseudo code: Convert the list of siteIDs to a prototype array and for each found array element, run a function passing the individual site id. $A(siteIDs) converts the list of site ids to an array, while .each() executes the inline function for each array element.
// $A(siteIDs).each(function(siteID)
If an element exists on the page with the id starting with setCurrentSiteElementPrefix (definition not shown here) + current siteID (passed by the inline function above)
// if ($(this.setCurrentSiteElementPrefix + siteID))
Add an observer to the "click" event of that element and bind it to the "getContent" function. The "getContent" function has to bound to the "this" scope since the "getContent" function will not otherwise know what "this" means when trying to refer to elements defined in the object.
// $(this.setCurrentSiteElementPrefix + siteID).observe('click', this.getContent.bind(this));
I was trying to tie an event observer to the 'click' event of each link element by looping through the list of dynamic ids ($A(siteIDs).each(function(siteID)). However, that was giving me some issues with the message "this.getContent is not defined". Why the heck not, the code is inside the "initialize" method of my object?! It turns out while looping over an array as above the "this" scope is not preserved. So the function inside the loop has no idea what "this" means. The simple fix is to surround the function with parenthesis and append ".bind(this)":
initialize: function() {
// Note the extra parenthesis before 'function(siteID)'
$A(siteIDs).each((function(siteID) {
if ($(this.setCurrentSiteElementPrefix + siteID)) {
$(this.setCurrentSiteElementPrefix + siteID).observe('click', this.getContent.bind(this));
}
}).bind(this));
// Note the ').bind(this)' before the semicolon
}
If you like to learn more on bind, check out Understanding bind and bindAsEventListener in Javascript and Understanding bind and bindAsEventListener in Javascript - Part II- Login or register to post comments
- 1789 reads
- Email this Quick Tip
- Printer-friendly version
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)







Comments
Juriy Zaytsev replied on Wed, 2008/02/06 - 7:36pm
This looks like a terrible practice to iterate over elements by their ids. Isn't using classes just so much easier?
$$('.myClass').invoke('observe', this.getContent.bind(this));As a side note, in version 1.6 "each" (or any other Enumerable method) accepts second argument and uses it as a scope for an iterator - the code becomes even more concise
CheersBoyan Kostadinov replied on Thu, 2008/02/07 - 8:47am
in response to: kangax
@Juriy, I agree with you. I wrote this before I started using the class names. However, the point of this quick tip is not the lack of my Prototype knowledge but the "bind" gotcha to be aware of when using enumeration.
------------------
Boyan Kostadinov
Blog: http://blog.tech-cats.com
Resume: http://boyan.tech-cats.com/resume
Portfolio: http://boyan.tech-cats.com/portfolio