I am developing custom widget for esri Web AppBuilder 2.16 (I have not yet upgraded to 2.17).
Seems as if lang.hitch spoils working with promises. What to do? Is there a solution? some code examples?
Help will be greatly appreciated,
Michael
Solved! Go to Solution.
Michael, if you can't get it working with lang.hitch, there is another way you can track scoping inside a class. Here is an example :
define([
//...
], function (
//...
) {
var that;
return declare(null, {
someData: '',
postCreate: function () {
that = this;
that.fetchSomeData().then(that.showData)
.otherwise(that.showError);
// instead of:
// this.fetchSomeData().then(lang.hitch(this, this.showData))
/// .otherwise(lang.hitch(this, this.showError));
},
fetchSomeData: function(){
var deferred = new Deferred();
someAsyncQuery().then(function(response){
that.someData = response;
deferred.resolve(response);
}).otherwise(function(error){
deferred.reject(error);
});
return deferred.promise;
},
showData: function(response){
alert(response);
},
showError:function(error){
alert(error);
}
});
});
I think lang.hitch does the job, but it makes the code really hard to read.
Can you provide some examples where it isn't working?
Dear Ken,
Only tomorrow I will be by my PC,
so I’ll try to explain:
I have custom widget and 2 classes (each in a file).
in the widget I want to do chain calls (with then) to several funcs from one class.
A func in the 2nd class calls function from 3rd class which in turn calls another async func in same 3rd class which returns promise.
Funcs in 2nd class could chain other funcs in the 2nd classs, using then.
And in all of this, I have to use Lang.hitch in order to keep tracking “this”.
I get errors complaining that the promise result is not defined, specially in “catch”.
It seems also that if I call the “chained” function within same 2nd class with lang.hitch, then I get error that “this.<funcname> is not known.
Tomorrow I’ll be able to send code.
(what I am trying to do, is to adapt the code exampleFME Server Playground to be a custom widget, so that the user will need only to choose the input file, but all other operations like getting info from workspace and uploading the input file and doing transformation, all will be done automatically one after the other by promises, where I don’t need all the html don element stuff.
Thanks for your willingness to help,
Michael
Michael, if you can't get it working with lang.hitch, there is another way you can track scoping inside a class. Here is an example :
define([
//...
], function (
//...
) {
var that;
return declare(null, {
someData: '',
postCreate: function () {
that = this;
that.fetchSomeData().then(that.showData)
.otherwise(that.showError);
// instead of:
// this.fetchSomeData().then(lang.hitch(this, this.showData))
/// .otherwise(lang.hitch(this, this.showError));
},
fetchSomeData: function(){
var deferred = new Deferred();
someAsyncQuery().then(function(response){
that.someData = response;
deferred.resolve(response);
}).otherwise(function(error){
deferred.reject(error);
});
return deferred.promise;
},
showData: function(response){
alert(response);
},
showError:function(error){
alert(error);
}
});
});
I think lang.hitch does the job, but it makes the code really hard to read.
Dear Carlos,
Thank you very much for the example code.
I came to a conclusion that lang.hitch can't return regular javascript promise.
So currently I'm using regular javascript promises, and I bypass the lang.hitch by using "that = this".
I'll update when I succeed (or have more problems...).
May I ask some questions, please?
Michael
Hi Michael.
1. Yes, regular javascript promises will work with lang.hitch. Here is a sample code:
define([
'dojo/_base/declare',
'dojo/_base/lang',
'jimu/BaseWidget'
], function (
declare,
lang,
BaseWidget
) {
return declare([BaseWidget], {
onOpen: function(){
var shouldFail = false;
this.fetchMessage(shouldFail).then(lang.hitch(this, this.processMessage))
.then(lang.hitch(this, this.showMessage))
.catch(lang.hitch(this, this.showMessage));
},
fetchMessage: function (shouldFail) {
var milisseconds = 2000;
return new Promise((resolve, reject) => {
setTimeout(function () {
if (shouldFail) {
reject('Error message');
} else {
resolve('Success message');
}
}, milisseconds);
});
},
processMessage: function (message) {
var milisseconds = 2000;
return new Promise((resolve, reject) => {
setTimeout(function () {
var processedData = "Processed " + message;
resolve(processedData);
}, milisseconds);
});
},
showMessage:function(message){
alert(message);
}
});
});
2. dojo/Deferred is a dojo module that implements Promises. I've noticed there is some diference between Deferred and regular javascript Promises, but the intent is the same for both of them. It seems better to use dojo/Deferred, because you can guarantee that this module will work in many browsers that dojo supports. Regular javascript Promises won't work in some browser versions, Internet Explorer 11 for example (check more here: https://caniuse.com/#search=Promise). Also, many, if not all, jimu modules implemented by ESRI use dojo/Deferred. By choosing it, you will prevent using 2 different modules that do the same thing, this reduces the amount of complexity to maintain your code and to understand ESRI code. Here is the documentation for the interface of dojo/promise: https://dojotoolkit.org/reference-guide/1.10/dojo/promise/Promise.html#dojo-promise-promise.
Dear Carlos,
I appreciate you very much for your explanations and code examples!
I’ll learn from them.
Meantime, today I have implemented by javascript promises, using class-scope “that” as you suggested,
and avoiding lang.hitch, and the promises work perfect!
Now that I read your reply,
I have to:
You helped me very much in learning that area, and the idea of class-wide “that” helped me very much.
With appreciation,
Michael
Found that lang.hitch can't return a Promise.
Michael