Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Gotcha with Prototype.Bind and Arrays

DZone's Guide to

Gotcha with Prototype.Bind and Arrays

· Web Dev Zone
Free Resource

Never build auth again! Okta makes it simple to implement authentication, authorization, MFA and more in minutes. Try the free developer API today! 

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

Launch your application faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}