I am using jQuery Deferred. I want to do 2 things when I click on a link to open modal dialog;
Call my API
Call my template (where values from API would get populated)
So I am doing the following;
self.myModel = new myModel();
self.myModel.url = "api/myModel/";
self.scenarioRecInfoDeferred = new $.Deferred();
self.myModel.fetch({
success : function(){
myModelDeferred.resolve();
}
});
self.tmplDeferred = new $.Deferred();
$.when(self.myModelDeferred, self.tmplDeferred).done(function(modalTemplates) {
});
require(['text!templates/mytemp/my-tpl.html'], function(modalTemplates) {
self.tmplDeferred.resolve(modalTemplates);
});
Now I am not getting anything for "modalTemplates" inside
$.when(self.myModelDeferred, self.tmplDeferred).done(function(modalTemplates) {}
Am I doing something wrong in accessing/passing the parameter?
I believe you need 2 parameters in your .done() function handler. The first parameter will correspond to myModelDeferred arguments (which will be undefined) and the second will correspond to tmplDeferred arguments.
I made a quick jsfiddle to test myself.
var action1 = $.Deferred();
var action2 = $.Deferred();
setTimeout(function(){
action1.resolve();
}, 1000);
setTimeout(function(){
action2.resolve("def", "ghi");
}, 500);
$.when(action1.promise(), action2.promise()).done(function(args, args2){
console.log(args); // undefined
console.log(args2); // ["def", "ghi"]
});
DEMO
Hope this helps!
Why do you need to declare the deferred before loading the template?
You could do whatever you need to do with modalTemplates inside that require block and just skip the tmplDeferred use at all.
require(['text!templates/mytemp/my-tpl.html'], function(modalTemplates) {
self.myModelDeferred.done(function(modalTemplates) {
});
});
Anyway, if you want to stick to that structure, I don't think that's the way to pass a variable to a deferred. You could instead assign it as self.tmplDeferred.modalTemplates=modalTemplates. So, the next should work
$.when(self.myModelDeferred, self.tmplDeferred).done(function(self.tmplDeferred.modalTemplates) {
});
require(['text!templates/mytemp/my-tpl.html'], function(modalTemplates) {
self.tmplDeferred.modalTemplates=modalTemplates;
self.tmplDeferred.resolve();
});
Related
I have tried to execute 4 function in a row inside dojo domready block and also i want to set a Boolean flag after the execution of these functions, but all function are fired in order asynchronously and the flag is set before the completion of these function i.e. the functions doesn't wait for the previous function to complete, they all are just started and move to the next one.
require([ 'dojo/domReady!' ], function() {
boolean flag=false;
function1();
function2();
function3();
function4();
flag=true;
});
How to set the flag only after the execution of all the 4 functions
I am sharing my original code, first i am executing the initial call in dojo ready, where i am setting the flag onload to false first
require([ 'dojo/domReady!' ], function() {
onload = false;
getQuoteOption();
});
then in the function 'getQuoteOption()' i am firing an ajax call to get fetch some json data
function getQuoteOption(){
var reqParams = addQuoteReqParams(reqParams);//getting json input data
var request = require("dojo/request");
request.get(url, {
query : {
inputJson : reqParams
},
handleAs : "json",
preventCache : true
}).then(function(response) {
configureQuoteFieldData(response);
configureIrregularFrequencyData(response);
onload=true;
}, function(error) {
console.log(error);
});
}
in the callback of the ajax call i am executing two functions 'configureQuoteFieldData(response)' and 'configureIrregularFrequencyData(response)' and then setting the flag onload to true believing the two former functions have executed completely but the flag onload is set to true before that.
for referring i am listing two function also here
function configureQuoteFieldData(quoteFieldData) {
var registry = require("dijit/registry");
registry.byId('form_quoteData').set('value', quoteFieldData);//setting data to form
}
function configureIrregularFrequencyData(obj) {
var tmpArray = [];
for (var i in obj) {
tmpArray.push(obj[i]);
}
irregularPayMonths['irregularData'] = tmpArray;//saving to global variable
}
You have to write your functions to accept a callback or return a promise. Then trigger the subsequent function with that instead of just calling it immediately.
Consider using dojo/promise/all and dojo/Deferred, the idea is to use deferred objects as mentioned by #Quentin.
Below a live example using specifically dojo framwork.
https://jsfiddle.net/9khdr4qa/
Explanation:
The code runs 3 functions which will return asynchronously, each function return at a different time as indicated by setTimeout().
Now you wish to set your flag to true, only after all 3 functions are returned and done.
The solution include a deferred object in each function. When the function return the deferred object is Fulfilled.
Use dojo/promise/all to detect when all 3 functions are returned. Basically its callback will run only after all 3 deferred objects are marked as Fulfilled.
Than set you flag to true and carry on with your code.
You can read more about dojo promises and deferred object here:
http://dojotoolkit.org/reference-guide/1.10/dojo/promise.html
https://dojotoolkit.org/reference-guide/1.10/dojo/Deferred.html
require(["dojo/promise/all", "dojo/Deferred", "dojo/dom", "dojo/on", "dojo/json", "dojo/domReady!"],
function(all, Deferred, dom, on, JSON) {
var flag = false;
function requestA() {
var deferred = new Deferred();
setTimeout(function() {
deferred.resolve("requestA");
}, 500);
return deferred.promise;
}
function requestB() {
var deferred = new Deferred();
setTimeout(function() {
deferred.resolve("requestB");
}, 750);
return deferred.promise;
}
function requestC() {
var deferred = new Deferred();
setTimeout(function() {
deferred.resolve("requestC");
}, 1000);
return deferred.promise;
}
on(dom.byId("startButton"), "click", function() {
dom.byId("output").innerHTML = "Running...";
all([requestA(), requestB(), requestC()]).then(function(results) {
dom.byId("output").innerHTML = JSON.stringify(results);
flag = true;
alert('Your flag is set to: ' + flag);
});
});
});
<h1>Click to start:</h1>
<pre id="output"></pre>
<button type="button" id="startButton">Start</button>
With the code snippet shared, the flag will be set after executing all the 4 functions. But, that does not mean that it has completed executing all the logic within those function. If there are some asynchronous calls within those functions then they will be executed after the flag is set.
If you could share the code within those functions, then we could give more specific solution.
UPDATE:
I believe the code for getting the registry, may be causing the problem.
var registry = require("dijit/registry");
The require gets the js file if it is not already retrieved from the server. that might be what is happening in your case. Try to have only one single require per script file. that way all the required files are retrieved before execution.
require(["dijit/registry","dojo/request", "dojo/domReady!"], function(registry, request) {
function getQuoteOption(){
var reqParams = addQuoteReqParams(reqParams);//getting json input data
request.get(url, {
query : {
inputJson : reqParams
},
handleAs : "json",
preventCache : true
}).then(function(response) {
configureQuoteFieldData(response);
configureIrregularFrequencyData(response);
onload=true;
}, function(error) {
console.log(error);
});
}
function configureQuoteFieldData(quoteFieldData) {
registry.byId('form_quoteData').set('value', quoteFieldData);//setting data to form
}
function configureIrregularFrequencyData(obj) {
var tmpArray = [];
for (var i in obj) {
tmpArray.push(obj[i]);
}
}
onload = false;
getQuoteOption();
});
Make sure the order of module and corresponding function parameters are matching.
I want to have one callback function after actions are done, I'm trying something like this:
$.when(
$('#detail1').load('/getInfo.php'),
$('#detail2').load('/getOther.php')
).then(function(a,b){
alert("done");
});
The problem is that the callback function is firing before the actions are finished.
This is because jQuery.when() expects jQuery.Deferred instances while load() returns an jQuery instance (see http://api.jquery.com/jQuery.when/ and http://api.jquery.com/load/).
You can work around this issue:
// Create two Deferred instances that can be handed to $.when()
var d1 = new $.Deferred();
var d2 = new $.Deferred();
// Set up the chain of events...
$.when(d1, d2).then(function() {
alert('done');
});
// And finally: Make the actual ajax calls:
$('#detail1').load('/getInfo.php', function() { d1.resolve(); });
$('#detail2').load('/getOther.php', function() { d2.resolve(); });
I do a similar code but for images in a more dynamic way. Hope that it help.
var deferreds = [];
// Create a deferred for all images
$('.my-img-class').each(function() {
deferreds.push(new $.Deferred());
});
var i = 0;
// When image is loaded, resolve the next deferred
$('.my-img-class').load(function() {
deferreds[i].resolve();
i++;
});
// When all deferreds are done (all images loaded) do some stuff
$.when.apply(null, deferreds).done(function() {
// Do some stuff
});
Hi I am using Jquery and ember to delete certain elements ,I want to use Deferred objects to stop the code and then next statements has to be executed
Here KillMany is Function once it is called it will execute array.forEach(tryKill);
statement
that contains an array of elemets[array contains 100 elements inside for each each time a call back is calling to delete the each element from server]
Here I want to execute my code after completely finishing [deletion of elements] myFinalblock callback has to be calle
please guide me
killMany: function(c) {
var t = this
, wait = []
, dfd = new $.Deferred();
function keep(tile) {
tile.setProperties({ isSelected: false, isHidden: false });
}
function destroy(tile) {
if (t.get('reports')) {
t.get('reports').removeObject(tile.entity);
}
tile.remove.bind(tile);
}
function tryKill(tile) {
tile.set('isHidden', true);
tile.get('entity').kill()
.then(destroy.bind(null, tile),
keep.bind(null, tile));
}
function myFinalblock(){
this.set('selectedTiles', []);
}
this.set('promptDestroyMany', false);
if (c.response) {
var array = this.get('selectedTiles');
array.forEach(tryKill);
myFinalblock();
}
},
You seem to be missing the point of promises a bit. They do not "stop" your code. They allow you to cleanly route your code's asyncrhonous functionality. Therefore you need a way to wait until all of the tryKill calls are done before calling myFinalBlock. To do this, you first need to modify your tryKill function to return its promise:
function tryKill(tile) {
tile.set('isHidden', true);
return tile.get('entity')
.kill()
.then(destroy.bind(null, tile),
keep.bind(null, tile));
}
Then you can do this:
var tiles = this.get('selectedTiles');
$.when.apply($, tiles.map(tryKill))
.then(myFinalBlock)
.done();
On a side note, I suggest looking into a proper promise library and not using jQuery's built-in deferreds, as they are known to have a number of problems.
I need for a function to be executable only after an object is defined, I'm currently working in a fascade pattern and one method is dependent on another method. in this case 'addNewLayer' fails because 'setFullMap' hasn't finished executing. is there a solution? I'm using jquery and vanilla js so most any solution would be helpful at this point:
var jen = (function(){
function setFullMap(mapID){
jen.map = new Map(mapID);
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id);
addNewLayer(opt);
}
};
})();
Thanks
solution:
var jen = (function(){
function setFullMap(mapID, callback) {
jen.map = new Map(mapID);
if(jen.map){
callback();
}
}
return {
samp: function(id, opt){
setFullMap(id, function(){
addNewLayer(opt);
}.bind(this));
}
};
})();
You will have to pass a callback function to setFullMap, and execute it once the function has completed (at the very end, before the closing }).
var jen = (function(){
function setFullMap(mapID, callback){
jen.map = new Map(mapID);
callback();
}
function setLayer(opt){
//execute code here after jen.map is defined
}
return{
samp: function(id, opt){
setFullMap(id, function() {
addNewLayer(opt);
}.bind(this));
}
};
})();
Do not forget using .bind(this) - it is very important in order to keep the original this in your callback function.
Edit:
Actually that would not work work if the Map constructor is a-synchronous. If you do not have access to the constructor and/or you cannot pass it a callback, then presumably the only (and sad) option would be to use a setTimeout or (easier) setInterval, continuously checking at defined intervals if the operation has been completed, and then fire the callback.
You could use a callback parameter:
function setFullmap(mapId,callback) {
jen.map = new Map(mapId);
callback();
}
....
samp: function(id, opt){
setFullMap(id,function() {
addNewLayer(opt);
});
}
When u dont have a way to manipulate the Map Object then u need to use a loop:
var loop=self.setInterval(function(){
if(jen.map) {
//execute code here after jen.map is defined
console.log(typeof jen.map);
window.clearInterval(loop);
}
},50);
Check jsfiddle:
http://jsfiddle.net/9yv5t/1/
I have checked the docs and it seems that there are various events you could listen to.
For example:
var m = new Map(...);
m.on('load', function () {
//execute code when the first layer is ready
});
var l = new Layer(...);
l.on('load', function () {
//execute code when the layer has been initialized
});
It's also carefully stated for the Layer.load event:
fires after layer properties for the layer are successfully populated.
This event must be successful before the layer can be added to the
map.
My main goal is to delay a counter before it triggers.
Imagine a timeout couting down 'n' to '0' and then fire an event, but it can be reset asyncly to 'n' every time something happens.
I tried to achieve this using 'promises' with $q.
I was trying to add dynamicly new promises with timeout inside chaining a brand new delay.
But before achieve this goal, i couldn't even chain new promises.
Example:
var d1 = $q.defer();
var d2 = $q.defer();
d1.promise.then(function(data) {
return 'd1' + data;
});
d2.promise.then(function(data) {
return 'd2' + data;
});
var t = $q.all([d1.promise]);
t.then(function(data) {
console.log(data);
});
$timeout(function()
{
d1.resolve("1000");
}, 1000);
$timeout(function()
{
t.then(function() {
d2.resolve("800");
});
}, 800);
It only outputs: ["1000"] instead of ["1000", "800"]
My search so far:
stackoverflow did not helped me.
angular-promise-tracker I can't understand this code, how it behaves is exactly for what I need. But it is made for something else.
If you are willing to just use native javascript then this should work:
// create a handle to the timeout
var toHandle = window.setTimeout(X);
// put this in the event that causes a reset
window.clearTimeout(toHandle);
toHandle = window.setTimeout(X);
Where X is the function you want to occur on a delay. This also gives you the power to change the delay value as you wish.
Cheers.