Reputation: 9292
I'm developing a jQuery plugin, which pretends to translate elements on the page, automatically depending on the user's browser language. Translations will be stored in .json files.
When you call the plugin, you pass a package name (or an Array of them) and then it will try to load the language file in the following way:
'en'
and you only have indicated a package, it will try to load the following: packageName-en.json
packageName-en.json
AND packageName-en-US.json
So, in the plugin I have this:
$.fn.Translator = function(pkg, options){
Translator.initialize(pkg, options).done(function(){
return this.each(Translator.translate);
});
};
So, somewhere in my initialize function, I have this:
loadLanguages : function(){
$.each(self.options.packages,function(i, pkg){
});
}
Which will call this function :
getLanguage : function(pkg, language){
var self = this, url;
if (self.options.path)
url = self.options.path + '/';
url += [pkg, language].join('-');
return $.ajax ({
url : url,
dataType : "json",
cache : self.options.cache
});
}
The problem is that since that function will be called probably multiple times, I don't know how to make initialize
to return a promise which will be resolved once ALL of the functions have been called.
Upvotes: 0
Views: 1233
Reputation: 11436
I know you accepted an answer already but there is a much simpler way: use $.when.
function loadLanguages () {
return $.when.apply( $, $.map( self.options.packages, function( pkg ) {
return getLanguage(pkg, language);
}) );
}
Upvotes: 2
Reputation: 4368
To solve this problem you can create a dummy Deferrer (baseDfr) and return the dummy as result of initialize()
. The idea here is to call baseDfr.resolve()
when all getLanguage()
calls are done. We keep track of the number of getLanguage()
calls that are done using a counter. When the counter reaches 0, we call baseDfr.resolve()
.
We know when a getLanguage()
call is done using the then()
or done()
method on the returned deferrer by $.ajax
.
The code to solve this can be found below. Also, a working example (on some divs) can be found here: http://jsfiddle.net/c5NBr/. Open your console to see the messages appear in correct order.
var packages = [];
var count = 0;
var baseDfr = $.Deferred();
var language = "en";
function resolveFunction () {
// By using this approach it is possible to pass a
// parameter to this resolve function.
return function(){
if ( !(--count) ) {
// Until count is 0, we won't resolve the base
// deferrer object.
// As long as this isn't called, the function
// done() of initialize won't be called either.
baseDfr.resolve();
}
};
}
function getLanguage (pkg, language){
var self = this, url;
if (self.options.path)
url = self.options.path + '/';
url += [pkg, language].join('-');
return $.ajax ({
url : url,
dataType : "json",
cache : self.options.cache
}).promise();
}
function loadLanguages () {
$.each(self.options.packages,function(i, pkg){
getLanguage(pkg, language).then(resolveFunction());
});
return baseDfr.promise();
}
function initialize(options) {
packages = options.packages;
count = options.packages.length;
return loadLanguages();
}
var options = {
packages : $('div')
};
initialize(options).done(function(){
// This will only be called when baseDfr.resolve() is called.
console.log("Fired all getLanguage().");
});
Upvotes: 0