2

I have the following code to grab a value from a drop down menu and use it to change the renderer of the featureLayer. However, it does not update the legend. The legend just stays on the initial, default renderer at page load.

I have tried adding a callback function after the switch that would legend.refresh(). That did indeed refresh the legend every time I changed the renderer, but oddly it was "one behind," always changing the legend to reflect the previous renderer instead of the current.

getRenderer = function(rendererFromSelect) {
 renderer = rendererFromSelect.value;
 switch(renderer) {
  case "approval_rate":
  map.removeLayer(featureLayer);
  var generateRenderer = new GenerateRendererTask(featureLayerURL);
  var params = new GenerateRendererParameters();
  var classDef = new ClassBreaksDefinition();
  classDef.breakCount = 5;
  classDef.classificationField = "approval_rate";
  classDef.classificationMethod = "quantile";
  params.classificationDefinition = classDef;
  generateRenderer.execute(params, applyRenderer);
  function applyRenderer(renderer) {
   featureLayer.setRenderer(renderer);
  };
...other cases...
};

I have also tried this:

(1) Create a function to build the legend (2) Call this function when the body loads (3) Every time a new renderer is selected via drop down, legend.destroy() (4) Then, after the renderer ids changed and the feature layer loads, create legend again.

So here is my function to create the legend. (I declare it as a global variable and define it inside the scope of the AMD so I call access it from the HTML.) This works great.

createLegend = function(titleStr){
  legend = new Legend({
    map: map,
    layerInfos : [ {
      layer : featureLayer,
      title : titleStr
    } ]
  }, "legend");
 legend.startup();
};

And here is where I change the renderer, load feature layer again, destroy legend and recreate after feature layer loads.

getRenderer = function(rendererFromSelect) {
 renderer = rendererFromSelect.value;
 switch(renderer) {
  case "approval_rate":
   map.removeLayer(featureLayer);
   var generateRenderer = new GenerateRendererTask(featureLayerURL);
   var params = new GenerateRendererParameters();
   var classDef = new ClassBreaksDefinition();
   classDef.breakCount = 5;
   classDef.classificationField = "approval_rate";
   classDef.classificationMethod = "quantile";
   classDef.colorRamp = multiRamp;
   params.classificationDefinition = classDef;
   generateRenderer.execute(params, applyRenderer);
   function applyRenderer(renderer) {
     featureLayer.setRenderer(renderer);
   };
   legend.destroy()
   map.addLayer(featureLayer);
   map.removeLayer(highlightLayer);
   map.addLayer(highlightLayer);

   break;
   ....other cases...
 }
  featureLayer.on("update", createLegend(renderer));
}

When I try this approach, the legend is created successfully when the page loads initially. The legend.destroy() is also working properly. However, when createLegend is called again to rebuild the legend with the new renderer, I get init.js:148 Uncaught TypeError: Cannot read property 'firstChild' of null

So I'm wondering if legend.destroy() destroys something that I need to create the legend again later?

EDIT: Indeed, legend.destroy() was eliminating the destination div for my legend. So I now recreate that div before I build the legend. Now the legend refreshes almost correctly, but it is still refreshing based on the PREVIOUS renderer.

I tried calling createLegend on "update-end" instead of "update". That seemed to make no difference.

2
  • Have you tried refreshing the legend when the "update-end" event fires?
    – kenbuja
    Commented Apr 1, 2016 at 13:22
  • Thanks, good idea. I just tried that and it made no difference, though. (See edit above) Commented Apr 1, 2016 at 13:42

1 Answer 1

2

In one of my applications, I'm using a combobox "cboDisplay" that switches the renderer for a featurelayer and updates the legend. The renderers were UniqueValueRenderers

    registry.byId("cboDisplay").on('change', function (evt) {
        var legendTitle = this.domNode.innerText;
        switch (evt) {
            case 0:
                layerFeatureLayer.setRenderer(rendererPriority);
                break;
            case 1:
                layerFeatureLayer.setRenderer(rendererManagement);
                break;
            case 2:
                layerFeatureLayer.setRenderer(rendererCriteria1);
                break;
            case 3:
                layerFeatureLayer.setRenderer(rendererCriteria2);
                break;
            case 4:
                layerFeatureLayer.setRenderer(rendererCriteria3);
                break;
        }
        layerFeatureLayer.redraw();
        legend.refresh([{
            layer: layerFeatureLayer,
            title: legendTitle
        }]);
    });

The storeDisplay looked like this:

    storeDisplay = new Memory({
        data: [
            { label: "Priority", id: 0 },
            { label: "Management Issue", id: 1 },
            { label: "Primary Criteria", id: 2 },
            { label: "Secondary Criteria", id: 3 },
            { label: "Tertiary Criteria", id: 4 }
        ]
    });

This was the way I was creating the legend to start. I was checking to see if the legend already was existing to due a workflow where another user would log in using OAuth and the page would be redrawn.

function createLegend() {
    if (legend) {
        legend.destroyRecursive(true);
    }
    if (legendDiv === undefined) {
        legendDiv = domConstruct.create("div", {
            id: "legendDiv"
        }, dom.byId("legendWrapper"));
    }

    legend = new Legend({
        map: map,
        layerInfos: [{
            layer: layerFeatureLayer,
            title: "Priority"
        }]
    }, legendDiv);
    legend.startup();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.