Scope Correction with YUI
Thursday, March 26th, 2009The more I use the Yahoo User Interface Library (YUI), the more I am impressed with it. I have been converting my JQuery imValidateForm plugin to a YUI widget for a project that I am working on. I ran into a scope issue when a button was clicked. I have dealt with Javascript scope issues in the past, but I did not know how to fix it using YUI. For those of you who are not familiar, the ‘this’ keyword within a function refers to the object itself.
function artist() { this.name = ‘Bob Marley’; } |
In the example above, the ‘this’ keyword refers to the artist object. Here’s a more complex example:
function cart(id) { this.selectedItem = id; var btnSubmit = document.getElementById(‘submit’); btnSubmit.onclick = function() { var selected = this.selectedItem; }; } |
Javascript does not know what ‘this.selectedItem’ is because the ‘this’ is in the scope of the btnSubmit object. To get around the scope issue, I can do the following:
function cart(id) { this.selectedItem = id; var self = this; var btnSubmit = document.getElementById(‘submit’); btnSubmit.onclick = function() { var selected = self.selectedItem; } } |
‘self’ is the cart object, not the submit button. Simple scope correction. But there are times when Javascript applications become so complex that scope correction is not this easy. In these situations, I have to do more than add self = this. I found a simple function that handles scope correction:
function cart(id) { this.selectedItem = id; var self = this; var btnSubmit = document.getElementById(‘submit’); btnSubmit.onclick = function() { bindCallBack(getAlbums, self, self.selectedItem); } this.getAlbums = function(id) { }; } function bindCallBack(fn, scope) { var args = []; for (var n = 1; n < arguments.length; n++) args.push(arguments[n]); return function () { return fn.apply(scope, args); }; } |
Without the bindCallBack function, the button would be able to ‘see’ the getAlbums method because it is out of scope. (Note: I can also use the bindCallBack function to pass parameters to the getAlbums).
The YUI way
So I didn’t want to deal with scope correction when creating my YUI widget, but as it turns out, I did not have to because YUI has automatic scope correction.
function cart() { this.selectedItem = null; var btnSubmit = YAHOO.utils.Dom.get(‘submit’); btnSubmit.on("click", this.getAlbums, this, true); this.getAlbums = function() { }; } |
By adding ‘this’ (the cart object) and ‘true’ to the click event, the execution scope of the button click is now the cart object. Easy. Try it yourself.



March 26th, 2009 at 12:55 pm
You can also write it as:
.on(“click”, this.getAlbums, null, this)
which I prefer. Also for regular JS scope-correction function.call and function.apply are very handy to know about.
https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Function/Apply
https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Objects/Function/Call
Pat Cavit’s last blog post..YUI Uploader Updated
March 28th, 2009 at 8:30 pm
Interesting. I wish I could also pass a value.
March 28th, 2009 at 10:43 pm
@admin:
Passing more argument along with the scope is a build-in feature in YUI3.x. You can emulate it on YUI2 using “apply”, but you have to do it manually, like your method “bindCallBack”.
Here is the YUI3 documentation:
http://developer.yahoo.com/yui/3/event/
Check the section: “Using on: Controlling Context and Arguments”.
March 29th, 2009 at 4:29 pm
Thanks. I’ve actually learned a lot about building widgets from visiting your site.
March 29th, 2009 at 4:32 pm
You can pass a value, using normal YUI:
.on(”click”, this.getAlbums, value, this)
You can pass values w/ .apply & .call as well.
.apply:
func_name.apply(scope, singleArg)
func_name.apply(scope, [multiple, args])
.call
func_name.call(scope, singleArg)
func_name.call(scope, multiple, args)
Using scope correction in JS is pretty simple & super-useful.