I'm trying to use some Object Oriented Javascript to keep my code clean rather than have a giant messy script like usual. Using Ajax is making this complicated, with its Asynchronous nature, its difficult to separate code.
A specific problem I am having is setting object properties with Ajax.
I have the following code:
var Class = function(){
this.attr1;
}
Class.prototype.setAttr1 = function(){
var self = this;
$.ajax({
url:'http://api.something.com?get=somedata',
success: function(data){
self.attr1 = data.name;
}
});
}
This should work, but I can't really be certain that the property is set if I access it from somewhere else, correct? Is there a way to deal with that. Like if I need to use attr1
somewhere, can I wait for the ajax to return or something? Or if I'm totally off, how to people encapsulate code when using Ajax?
This should work, but I can't really be certain that the property is set if I access it from somewhere else, correct?
Correct
Is there a way to deal with that. Like if I need to use attr1 somewhere, can I wait for the ajax to return or something?
Yup: Where you want to use attr
, have the accessor accept a callback (directly, or indirectly by returning a promise), and have it call the callback (or resolve the promise) when the attribute is available.
It looks like you want to keep the code that initiates the ajax call separate from the code that uses the attribute value later. If so, a promise-based mechanism will probably be more useful in this situation. As you're using jQuery, here's a jQuery example using jQuery's Deferred
and Promise
:
var Class = function(){
this.attr1LoadDeferred = $.Deferred();
}
Class.prototype.setAttr1 = function(){
var self = this;
$.ajax({
url:'http://api.something.com?get=somedata',
success: function(data){
self.attr1 = data.name;
self.attr1LoadDeferred.resolveWith(self);
}
});
}
Class.prototype.accessAttr1 = function() {
return this.attr1LoadDeferred.promise();
};
Usage:
// Create an instance
var c = new Class();
// At some point, initiate loading the value
c.setAttr1();
// At some point, look to use the value
c.accessAttr1().then(function(inst) {
console.log(inst.attr1);
});
// Somewhere else, look to use the value
c.accessAttr1().then(function(inst) {
doSomethingElseWith(inst.attr1);
});
Unfortunately, jQuery's Deferred
/Promise
implementation has an issue that most promises libraries don't: The callback you pass then
will sometimes be called asynchronously, other times synchronously. (Specifically: If the promise is already resolved, the callback is synchronous.) Either just keep that in mind when using it, or use a different promise implementation.
Typically, you would either:
Pass around callbacks or promises which would let your code wait for the values to be set; the jQuery framework makes heavy use of callbacks, but also returns promises from its AJAX functions.
Have your objects raise events when attributes are changed. Backbone is a great example of a framework which makes heavy use of events.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With