Reputation: 2170
I have a module with four functions that call one after the other. I am trying to follow the Revealing Module Pattern. One of the functions is public, the remaining are private. It goes like this:
publicMethod
is called from another modulequeryNames
is called from publicMethod
execute(parameters, callback?, errback?)
is called from queryNames
addNamesList
is called as the callback?
argument of execute
dijit/form/CheckBox
's are created and the method querySegments
is triggered onChange
querySegments
needs to call a method of an object created in publicMethod
.The problem is in step 6, I can't reach the object created in step 1.
I have tried to use dojo hitch to define the callback?
argument in step 3, but I can't get it to work. I tried putting this
in its first argument, but even then I can't reach the required scope to call addNamesList
.
Here is some code to demonstrate this issue.
define([
'dojo/dom',
'dijit/form/CheckBox',
'esri/layers/ArcGISDynamicMapServiceLayer',
'esri/tasks/query',
'esri/tasks/QueryTask',
'dojo/_base/lang'
],
function (
dom,
CheckBox,
ArcGISDynamicMapServiceLayer,
Query, QueryTask,
lang
) {
// ***************
// private methods
// ***************
// fetch names and call addNamesList to put the list in place
var queryNames = function (map, mapLayer) {
// new QueryTask(url, options?)
var queryTask = new QueryTask("url")
var query = new Query()
// execute(parameters, callback?, errback?)
// this callback passes an argument called featureSet
queryTask.execute(query, lang.hitch(map, "addNamesList", mapLayer), function(error) {console.log(error)})
}
// callback function of queryNames
var addNamesList = function (mapLayer, featureSet) {
console.log('addOplist')
var namesCount = featureSet.features.length
for (var i = 0; i <namesCount; i++) {
// work
var cbox = new CheckBox({
id: "cbox_" + i,
value: featureSet.features[i].attributes["someID"],
checked: false,
onChange: function (evt) {
querySegments(this.value, mapLayer)
}
})
cbox.placeAt("someDiv" + i, "first")
}
}
// triggered by the checkbox event
var querySegments = function (name, mapLayer) {
// build the query
var queryStatement = "someID = " + name
var layerDefinitions = [queryStatement]
// call a method of mapLayer
mapLayer.setLayerDefinitions(layerDefinitions)
}
// **************
// public methods
// **************
var publicMethod = function (map) {
var mapLayer = new ArcGISDynamicMapServiceLayer('restURL')
map.addLayer(mapServiceLayer)
queryNames(map, mapLayer)
return mapLayer
}
return {
publicMethod: publicMethod
}
}
)
You can see a more detailed explanation and a working example on this other (and more broad) question that I have put on Code Review.
I am new to JavaScript and I guess I still have a lot of issues with scoping, closures and callbacks.
I will deeply appreciate any input, including how to improve this question.
With this current implementation (with dojo hitch), no error is thrown. The method addNamesList
is not called (nor errback
, which I also don't understand why). I think this is because addNamesList
is not on map
's (hitch first argument) namespace. I tried to put this
instead, but it makes no difference.
Before I decided to use hitch, the code looked like this:
var queryNames = function (map, mapLayer) {
...
queryTask.execute(query, addNamesList)
}
var addNamesList = function (featureSet) {
...
...
...
querySegments(this.value, mapLayer)
}
but then I couldn't reach mapLayer
inside the method triggered by the check box event. It would throw Uncaught ReferenceError: mapLayer is not defined
. That is why I tried to use hitch.
Upvotes: 4
Views: 2853
Reputation: 4565
Javascript is asynchronous, so pretty much data coming from db, http requests or whatever is returned via callbacks. Here's what happens in your code:
addNamesList
of map
asynchronously and returns nothingaddNamesList
mapLayer
is returned untouched while some stuff is still going on in the backgroundSo, to avoid this, you should return data from public method via callback, so you pass callback
as the second parameter to the public method, then to the querySegments. Then, in the success callback of query
, when you finally get the result ready, you do:
callback(mapLayer);
So, everything you should do is to pass this callback
as deep as needed to the place where you have your mapLayer
ready (so you've done with it everything you wanted), and then do a callback(mapLayer);
.
This and this would probably explain better.
Best regards, Alexander
Upvotes: 3