Joe
Joe

Reputation: 13

How to Handle Nested Dojo Deferreds

I am looking to query any attachments of layers based on the results of an Identify Task. If there are attachments on the layer, I would like to add the links to the bottom of the infoTemplate.

I am having trouble working the multiple dojo Deferred objects. I know they are being resolved because the return values are logged in the console, but my infoWindow is never populated.

So what is the proper way to deal with several nested deferreds? Deferred Lists seem to be a step in the right direction, but I am unsure how I would format one in this situation.

Thanks,

Joe

Update:

I have updated my working code below.

map.on('click',executeIdentify);

function executeIdentify(evt) {
  identifyParams.width = map.width;
  identifyParams.height = map.height;
  identifyParams.geometry = evt.mapPoint;
  identifyParams.mapExtent = map.extent;

  var deferred = identifyTask.execute(identifyParams);

  deferred.addCallback(function(deferredResult){
    var promiseList = []
    var features = array.map(deferredResult,function(result) {

      var feature = result.feature;
      var content = "";
      array.forEach(Object.keys(feature.attributes),function(attr) {
        content += attr + ": " + feature.attributes[attr] + "<br>"
      });
      var url = identifyTask.url + "/" + result.layerId + "/" + result.feature.attributes.OBJECTID + "/attachments?f=json"
      var req = esriRequest({url:url}).then(function(newDef) {

        if (Object.keys(newDef).toString() == "attachmentInfos,_ssl") {
          content += "<br><b>Attachments:</b><hr>"
          array.forEach(newDef.attachmentInfos,function(attach) {
            content += "<a href=" + identifyTask.url + "/" + result.layerId + "/" + result.feature.attributes.OBJECTID + "/attachments/" + attach.id + " target='_blank'>" + attach.name + "</a><br>"
          })
        }
        content += "<br><br>";
        console.log(result)
        feature.infoTemplate = new InfoTemplate(result.layerName + " " + result.feature.attributes.OBJECTID,content)
        // console.log(feature)
        return feature
      },function(newDef) {
        feature.infoTemplate = new InfoTemplate(result.layerName + " " + result.feature.attributes.OBJECTID,content);
        // console.log(feature)
        return feature
      });
      promiseList.push(req);
    });
    var promiseAll = new all(promiseList)
    promiseAll.then(function(r) {promiseFun(r)})
  })
  function promiseFun(r) {
    map.infoWindow.setFeatures(r);
    map.infoWindow.show(evt.mapPoint);
  }
}

Upvotes: 1

Views: 1182

Answers (1)

kenbuja
kenbuja

Reputation: 250

You should look at using dojo/promise/all to handle multiple deferred results. Here's an example that uses it to return the results from multiple services, with some extra code to identify which service the result is coming from.

    <!DOCTYPE html>  
<html>  
<head>  
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">  
    <!--The viewport meta tag is used to improve the presentation and behavior of the samples  
      on iOS devices-->  
    <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">  
    <title>Identify with Popup</title>  

    <link rel="stylesheet" href="http://js.arcgis.com/3.8/js/esri/css/esri.css">  
    <style>  
        html, body, #map {  
            height: 100%;  
            width: 100%;  
            margin: 0;  
            padding: 0;  
        }  
    </style>  

    <script>var dojoConfig = { parseOnLoad: true };</script>  
    <script src="http://js.arcgis.com/3.8/"></script>  
    <script>  

        var map;  
        var identifyTask, identifyParams, idPoint;  
        var identifyResults;  

        require([  
          "esri/map", "esri/dijit/Popup", "dojo/promise/all", "dojo/domReady!"  
        ], function (  
          Map, Popup, All  
        ) {  
            var popup = new Popup({  
                fillSymbol: new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID, new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID, new dojo.Color([255, 0, 0]), 2), new dojo.Color([255, 255, 0, 0.25]))  
            }, dojo.create("div"));  

            map = new Map("map", {  
                basemap: "satellite",  
                center: [-83.275, 42.573],  
                zoom: 18,  
                infoWindow: popup  
            });  

            dojo.connect(map, "onLoad", mapReady);  

            var landBaseLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/BloomfieldHillsMichigan/Parcels/MapServer", { opacity: .55 });  
            map.addLayer(landBaseLayer);  

            var militaryLayer = new esri.layers.ArcGISDynamicMapServiceLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/Military/MapServer", { opacity: .55 });  
            map.addLayer(militaryLayer);  


            function mapReady(map) {  
                dojo.connect(map, "onClick", runIdentifies);  
            }  

            function runIdentifies(evt) {  
                identifyResults = [];  
                idPoint = evt.mapPoint;  
                var layers = dojo.map(map.layerIds, function (layerId) {  
                    return map.getLayer(layerId);  
                });  
                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 promises = [];  

                for (i = 0; i < tasks.length; i++) {  
                    promises.push(tasks[i].execute(params[i])); //Execute each task  
                }  

                var allPromises = new All(promises);  
                allPromises.then(function (r) { showIdentifyResults(r, tasks); });  
            }  

            function showIdentifyResults(r, tasks) {  
                var results = [];  
                var taskUrls = [];  
                r = dojo.filter(r, function (result) {  
                    return r[0];  
                });  
                for (i = 0; i < r.length; i++) {  
                    results = results.concat(r[i]);  
                    for (j = 0; j < r[i].length; j++) {  
                        taskUrls = taskUrls.concat(tasks[i].url);  
                    }  
                }  
                results = dojo.map(results, function (result, index) {  
                    var feature = result.feature;  
                    var layerName = result.layerName;  
                    var serviceUrl = taskUrls[index];  
                    feature.attributes.layerName = result.layerName;  

                    var template = new esri.InfoTemplate("", "Service Url: " + serviceUrl + "<br/><br/>Layer name: " + result.layerName + "<br/><br/> Object Id: ${OBJECTID}");  
                    feature.setInfoTemplate(template);  

                    var resultGeometry = feature.geometry;  
                    var resultType = resultGeometry.type;  
                    return feature;  
                });  

                if (results.length === 0) {  
                    map.infoWindow.clearFeatures();  
                } else {  
                    map.infoWindow.setFeatures(results);  
                }  
                map.infoWindow.show(idPoint);  
                return results;  
            }  

            function createIdentifyParams(layers, evt) {  
                var identifyParamsList = [];  
                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) {  
                        var subLayers = [];  
                        for (var i = 0; i < layer.layerInfos.length; i++) {  
                            if (layer.layerInfos[i].subLayerIds == null)  
                                subLayers.push(layer.layerInfos[i].id);  
                        }  
                        idParams.layerIds = subLayers;  
                    } else {  
                        idParams.layerIds = [];  
                    }  
                    idParams.tolerance = 3;  
                    idParams.returnGeometry = true;  
                    identifyParamsList.push(idParams);  
                });  
                return identifyParamsList;  
            }  

        });  
    </script>  
</head>  

<body>  
    <div id="map"></div>  
</body>  

</html>  

Upvotes: 4

Related Questions