conversion of mutiple IdentifyTasks from DeferredList to Promise and All

1025
7
Jump to solution
10-02-2013 01:31 PM
TracySchloss
Frequent Contributor
I have been using this function on a map click event to run multiple identify tasks using deferred and deferredList.  I'm now hoping to get this rewritten to use dojo/promise/all.  I'm getting lost on what should be changed in this code.

Here is the original, and it works.
function runIdentifies(evt) { idPoint = evt.mapPoint;     var layers = dojo.map(map.layerIds, function(layerId) {         return map.getLayer(layerId);     }); //Create an array of all layers in the map     layers = dojo.filter(layers, function(layer) {         if (layer.visibleLayers[0] !== -1){         return layer.getImageUrl && layer.visible         }     }); //Only dynamic layers have the getImageUrl function. Filter so you only query visible dynamic layers     var tasks = dojo.map(layers, function(layer) {         return new esri.tasks.IdentifyTask(layer.url);     }); //map each visible dynamic layer to a new identify task, using the layer url     var defTasks = dojo.map(tasks, function (task) {         return new dojo.Deferred();     }); //map each identify task to a new dojo.Deferred     var params = createIdentifyParams(layers,evt);     var dlTasks = new dojo.DeferredList(defTasks); //And use all of these Deferreds in a DeferredList     dlTasks.then(showIdentifyResults); //chain showIdentifyResults onto your DeferredList     for (i=0;i<tasks.length;i++) { //Use 'for' instead of 'for...in' so you can sync tasks with defTasks         try {             tasks.execute(params, defTasks.callback, defTasks.errback); //Execute each task         } catch (e) {             console.log("Error caught");             console.log(e);             defTasks.errback(e); //If you get an error for any task, execute the errback         }     } } //needed to limit identify to only currently visible layers function createIdentifyParams(layers,evt){ identifyParamsList.length = 0; dojo.forEach(layers, function (layer) {     var idParams = new esri.tasks.IdentifyParameters();     idParams.width = map.width;     idParams.height = map.height;     idParams.geometry = evt.mapPoint;     idParams.mapExtent = map.extent;     idParams.layerOption = esri.tasks.IdentifyParameters.LAYER_OPTION_VISIBLE;     var visLayers = layer.visibleLayers;     if (visLayers !== -1) {     idParams.layerIds = layer.visibleLayers;     }else {     idParams.layerIds = [];     }     idParams.tolerance = 3;     idParams.returnGeometry = true;     idParams.spatialReference = spatialReference;     identifyParamsList.push(idParams);     });     return identifyParamsList; }  function showIdentifyResults(r) {     var results = [];     r = dojo.filter(r, function (result) {         return r[0];     }); //filter out any failed tasks     for (i=0;i<r.length;i++) {         results = results.concat(r[1]);     }      results = dojo.map(results, function(result) {         var feature = result.feature;          var layerName = result.layerName;         feature.attributes.layerName = result.layerName;          feature.setInfoTemplate(generateInfoTemplate);         var resultGeometry = feature.geometry;         var resultType = resultGeometry.type;             if (layerName == "House" || layerName == "Congressional" ) {             feature.attributes.nameTitle = "Representative ";             feature.setInfoTemplate(legisInfoTemplate);         }                              if (layerName == "Senate") {             feature.attributes.nameTitle = "Senator ";             feature.setInfoTemplate(legisInfoTemplate);         }           return feature;              });             if(results.length === 0) {                 map.infoWindow.clearFeatures();             } else {                 map.infoWindow.setFeatures(results);             }             map.infoWindow.show(idPoint);             return results; }   

Here's what I have so far, trying to substitute with Deferred and all.  Or should it be Promise and all?  From my reading, all and deferredList are very similar, but not so for Deferred vs. Promise
function createIdentifyParams(layers,evt){ identifyParamsList.length = 0; arrayUtils.forEach(layers, function (layer) {     var idParams = new IdentifyParameters();     idParams.width = app.map.width;     idParams.height = app.map.height;     idParams.geometry = evt.mapPoint;     idParams.mapExtent = app.map.extent;     idParams.layerOption = IdentifyParameters.LAYER_OPTION_VISIBLE;     var visLayers = layer.visibleLayers;     if (visLayers !== -1) {     idParams.layerIds = layer.visibleLayers;     }else {     idParams.layerIds = [];     }     idParams.tolerance = 3;     idParams.returnGeometry = true;     idParams.spatialReference = spatialReference;     identifyParamsList.push(idParams);     });     return identifyParamsList; }  function runIdentifies(evt) { idPoint = evt.mapPoint; //Create an array of all layers in the map     var layers = arrayUtils.map(app.map.layerIds, function(layerId) {         return app.map.getLayer(layerId);     });  //Only dynamic layers have the getImageUrl function. Filter so you only query visible dynamic layers     layers = arrayUtils.filter(layers, function(layer) {         if (layer.visibleLayers[0] !== -1){         return layer.getImageUrl && layer.visible         }     }); //map each visible dynamic layer to a new identify task, using the layer url      var tasks = arrayUtils.map(layers, function(layer) {         return new IdentifyTask(layer.url);     });      var defTasks = arrayUtils.map(tasks, function (task) {       //  return new dojo.Deferred();  // original code       return new Deferred();     }); //map each identify task to a new dojo.Deferred //function to create an array of parameters, limits identify to only visible layers     var params = createIdentifyParams(layers,evt);     var dlTasks = new all(defTasks);     // var dlTasks = new dojo.DeferredList(defTasks); //And use all of these Deferreds in a DeferredList, original code     dlTasks.then(showIdentifyResults);      for (i=0;i<tasks.length;i++) {          try {             tasks.execute(params, defTasks.callback, defTasks.errback);          } catch (e) {             console.log("Error caught");             console.log(e);             defTasks.errback(e);          }     } }  function showIdentifyResults(r) {     var results = [];     r = dojo.filter(r, function (result) {         return r[0];     }); //filter out any failed tasks     for (i=0;i<r.length;i++) {         results = results.concat(r[1]);     }      results = arrayUtils.map(results, function(result) {         var feature = result.feature;          var layerName = result.layerName;         feature.attributes.layerName = result.layerName;          feature.setInfoTemplate(generateInfoTemplate);         var resultGeometry = feature.geometry;         var resultType = resultGeometry.type;             if (layerName == "House" || layerName == "Congressional" ) {             feature.attributes.nameTitle = "Representative ";             feature.setInfoTemplate(legisInfoTemplate);         }                              if (layerName == "Senate") {             feature.attributes.nameTitle = "Senator ";             feature.setInfoTemplate(legisInfoTemplate);         }           return feature;              });             if(results.length === 0) {                 map.infoWindow.clearFeatures();             } else {                 map.infoWindow.setFeatures(results);             }             map.infoWindow.show(idPoint);             return results; }   
0 Kudos
1 Solution

Accepted Solutions
ZachLiu1
Occasional Contributor II
don't use "new all(defTasks)"

try to change it to:

all(defTasks).then(showIdentifyResults);



Actually "identifyTask.execute(identifyParams)" itself returns a dojo.Deferred object, so a cleaner code should be like this:

say you have a list of new IdentifyTask created from a list of layers, and also a list of new IdentifyParameters correspondingly.

The code would be
var IdentifyTaskList = arrayUtils.map(layers, function(layer, index) {         task = new IdentifyTask(layer.url);         return task.execute(params[index])     //assume you have a list of identifyParameters     });   all(IdentifyTaskList).then(function(Results){         //Results will be a list of Result generated by each IdentifyTask in the list })  


Hope this will help.

View solution in original post

0 Kudos
7 Replies
ZachLiu1
Occasional Contributor II
don't use "new all(defTasks)"

try to change it to:

all(defTasks).then(showIdentifyResults);



Actually "identifyTask.execute(identifyParams)" itself returns a dojo.Deferred object, so a cleaner code should be like this:

say you have a list of new IdentifyTask created from a list of layers, and also a list of new IdentifyParameters correspondingly.

The code would be
var IdentifyTaskList = arrayUtils.map(layers, function(layer, index) {         task = new IdentifyTask(layer.url);         return task.execute(params[index])     //assume you have a list of identifyParameters     });   all(IdentifyTaskList).then(function(Results){         //Results will be a list of Result generated by each IdentifyTask in the list })  


Hope this will help.
0 Kudos
TracySchloss
Frequent Contributor
I felt like I had several lines too many in that function, but it was a posting from another thread and jsFiddle, not my own.  Since it was functional, I just left it alone.  (Until now when I needed it changed!)

Since there's quite a bit that happens in my showResults function, I think I'll leave it separate for now.  That function isn't quite right yet, but I do see I have results returned.  I'm on much more comfortable ground there, so hopefully I'll get it all straightened out soon.
0 Kudos
TracySchloss
Frequent Contributor
Because the output from all(IdentifyTaskList).then(showIdentifyResults) isn't the same as my deferredList was, I had to deal with the results slightly differently. 
This is the new showResults function:
function showIdentifyResults(idResults) {
   generateInfoTemplate = new InfoTemplate();
   generateInfoTemplate.setContent(generateWindowContent);   

     results = arrayUtils.map(idResults, function(r) {
         var result = r[0];
        var feature = result.feature; 
        var layerName = result.layerName;
        generateInfoTemplate.setTitle("Layer Information");
        feature.attributes.layerName = result.layerName; 
        feature.setInfoTemplate(generateInfoTemplate);
        return feature;             
});

            if(results.length === 0) {
                app.map.infoWindow.clearFeatures();
            } else {
                app.map.infoWindow.setFeatures(results);
            }
            app.map.infoWindow.show(idPoint);
        //    return results;
}  
0 Kudos
ZachLiu1
Occasional Contributor II
That looks better. The bottom line is as along as all(promiseList).then(callback) works, you can do whatever you want with the resultList that is passed to your callback function.
0 Kudos
TracySchloss
Frequent Contributor
I have another project that has a series of queryTasks to populate datagrids that also needs to be changed.  This example should work just fine for that as well.  Thanks for your assistance.
0 Kudos
TracySchloss
Frequent Contributor
I discovered my showResults function doesn't work the way I intended.  The first time I tried it, it was OK because each of my dynamicmapservicelayers only had one layer each in it.  When I began adding additional dynamiclayers that had more than that, I realized I wasn't processing all the layers, only the first one.  I need to loop through this differently not just use r[0], which obviously only grabs the first layer from each returned!:(

I'm sure I need to check the length of r and loop do something with that, but I'm not sure if that goes within my arrayUtil. map or outside of it.  It seems like results needs to be an array of all features from all layers of all processes, but I'm not sure how to get there.  The only thing I know for certain is that I am seeing all the features I expect, I'm just not getting them in the format needed for defining my infoWindow. 
function showIdentifyResults(idResults){
var results = [];
    results = arrayUtil.map(idResults, function(r){
            //loop here, something like for (i=0;i<rlength;i++??
            var result = r[0];    // r might have one layer turned on, might have had several    
            var feature = result.feature;
            var layerName = result.layerName;
            generateInfoTemplate.setTitle("Layer Information");
            feature.attributes.layerName = result.layerName;
            feature.setInfoTemplate(generateInfoTemplate);
            return feature;
        if (results.length === 0) {
            app.map.infoWindow.clearFeatures();
        }
        else {
            app.map.infoWindow.setFeatures(results);
        }
        app.map.infoWindow.show(idPoint);

    });
}   
0 Kudos
TracySchloss
Frequent Contributor
OK, I think this works:
function showIdentifyResults(idResults){
  var results = [];
   idResults = arrayUtil.filter(idResults, function (result) {//filter out any failed tasks
      return idResults[0];
   }); 
    for (i=0;i<idResults.length;i++) { //combines identifyResults 
        var lyrResultLen = idResults.length;
        var lyrResult = idResults;
        for (j = 0; j < lyrResultLen; j++) {
          var featRes = lyrResult;
          results.push(featRes);
        }
    }
    formatResults = arrayUtil.map(results, function(result){        
        var feature = result.feature;
        var layerName = result.layerName;           
        feature.attributes.layerName = result.layerName;
        feature.setInfoTemplate(generateInfoTemplate);
        generateInfoTemplate.setTitle("Layer Information");
        return feature;            
     });
        if (formatResults.length > 0) { 
         app.map.infoWindow.setFeatures(formatResults);
         app.map.infoWindow.show(idPoint);
        }      
} 
0 Kudos