So I am building a Javascript router and building a route like this:
route('/user/{name}', 'page', function() {
this.text = 'User: ' + this.name;
});
The scope of the function is the current route, so I can manipulate the current route here (this.text is what the view is looking for).
Now my next step is to include an XHR request within the route, which would look something like:
route('/user/{name}', 'page', function() {
this.text = 'Loading';
var request = new XMLHttpRequest();
request.open('GET', '/api/user', true);
request.onreadystatechange = (function() {
if (this.readyState === 4) {
if (this.status >= 200 && this.status < 400) {
var data = JSON.parse(this.responseText);
// here is the issue: 'this' now refers to
// the XHR request and not the scope of the router
this.age = data.age;
this.gender = data.gender;
} else {
this.text = "Error";
}
}
})/* .bind(this); */ // keeping scope like this overwrites the XHR
request.send();
request = null;
});
The issue here is that I need to access the XHR scope and my router's scope. Using .bind at the end of the onreadystatechange would over write the XHR scope, and not setting it overwrites the router's scope.
so wat do? Is there anything cleaner than var that = this;
-- surely there must be a way?
The simplest (and very clear way) is to keep the reference to route's scope like this:
var that = this;
Also you can set the scope using .bind()
and access request properties directly from reqest
variable.
And for your example (with bind
helper function, to support old browsers):
var bind = function(fn, context) {
return function() {
fn.apply(context, arguments);
};
};
request.onreadystatechange = bind(function() {
if (request.readyState === 4) {
if (request.status >= 200 && request.status < 400) {
var data = JSON.parse(request.responseText);
this.age = data.age;
this.gender = data.gender;
} else {
this.text = "Error";
}
}
}, this);