Select to view content in your preferred language

Registry Error in Custom Widget

2282
26
Jump to solution
01-24-2018 07:53 AM
AbhinavSharma
New Contributor III

//Updated define //

//updated last line from fields to fieldNames// 

Hi everyone, I am attempting to expand my widget by adding in a renderer that is is available to the end user. I have been working my way through the following ESRI Sample. The sample is for a mapservice and not a feature layer but I do not see why the same idea can not be applied. The issue is in bold. It stops at both of those instances. I have used console.log to see if there is any difference in the object that is being passed. ( Looked at the object in the sample and compared to my own) and the only difference i can find is when i print out fieldname after the push: using (console.log("fieldnames", fieldNames)

the sample looks like this:

fieldnames

  1. {identifier: "value", label: "name", items: Array(2)}
    1. identifier:"value"
    2. items:Array(10)
      1. 0:
        1. name:["FIPS"]
        2. value:["FIPS"]
        3. _0:0
        4. _RI:true
        5. _S:{_arrayOfAllItems: Array(10), _arrayOfTopLevelItems: Array(10), _loadFinished: true, _jsonFileUrl: undefined, _ccUrl: undefined, …}
        6. __proto__:Object 

whereas from my widget it looks like this:

fieldnames

  1. {identifier: "value", label: "name", items: Array(1)}
    1. identifier:"value"
    2. items:Array(19)
      1. 0:
        1. name:"OBJECTID"
        2. value:"OBJECTID"

TypeError: Cannot read property 'on' of undefined

define(
['dojo/_base/declare',
'jimu/BaseWidget',
"esri/toolbars/draw",
"esri/toolbars/edit",
"esri/graphic",
"esri/request",
"esri/config",
"esri/tasks/ClassBreaksDefinition",
"esri/tasks/UniqueValueDefinition",
"esri/tasks/AlgorithmicColorRamp",
"esri/tasks/GenerateRendererParameters",
"esri/tasks/GenerateRendererTask",
"esri/layers/LayerDrawingOptions",
"esri/layers/FeatureLayer",
"esri/layers/Field",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/dijit/editing/TemplatePicker",
"dojo/_base/array",
"dojo/_base/event",
"dojo/_base/lang",
"dojo/parser",
"dijit/registry",
"dojo/data/ItemFileReadStore",
"dojox/grid/DataGrid",
"dijit/form/FilteringSelect",
"dojo/domReady!"],
function(declare, BaseWidget, Draw, Edit, Graphic, esriRequest, esriConfig,
 ClassBreaksDefinition, UniqueValueDefinition, AlgorithmicColorRamp,
 GenerateRendererParameters, GenerateRendererTask, LayerDrawingOptions,
 FeatureLayer,Field,
 SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol,
 TemplatePicker,
 arrayUtils, event, lang, parser, registry, ItemFileReadStore, DataGrid, FilteringSelect) {
 //To create a widget, you need to derive from BaseWidget.
 return declare([BaseWidget], {
 // DemoWidget code goes here
//please note that this property is be set by the framework when widget is loaded.
 //templateString: template,
baseClass: 'jimu-widget-ROP',
postCreate: function() {
 this.inherited(arguments);
 console.log('postCreate');
 },
startup: function() {
 ///INICIO/////
 parser.parse();
// refer to "Using the Proxy Page" for more information: https://developers.arcgis.com/javascript/3/jshelp/ags_proxy.html
 esriConfig.defaults.io.proxyUrl = "/proxy/";
 map= this.map;
map.on("layers-add-result", initEditing);

 var landusePolygonLayer = new FeatureLayer("MyLayer", {
 id: "canada_Risk",//confirm works
 mode: FeatureLayer.MODE_ONDEMAND,
 outFields: ["*"]
 });
 console.log("LayerInfo", landusePolygonLayer)
 map.addLayers([landusePolygonLayer]);
//fieldInfo
 var canadaFields = esriRequest({
 url:"https://services7.arcgis.com/Layer",
 content:{
 f: "json"
 },
 callbackParamName : "callback"
 });
 console.log("fields", canadaFields)
 canadaFields.then(function(resp){
 var fieldNames, fieldStore;
fieldNames = { identifier : "value", label: "name", items: []};
 console.log("fields", fieldNames)
 arrayUtils.forEach(resp.fields,function(f){
 fieldNames.items.push({"name": f.name, "value": f.name});
 console.log("fieldnames", fieldNames)
 });
fieldStore = new ItemFileReadStore({ data:fieldNames});
 console.log("store", fieldStore)
 registry.byId("fieldNames").set("store", fieldStore);
 }, function(err){
 console.log("failed to get field names: ", err);
 });
 //update when field name changes
 registry.byId("fieldNames").on("change", getData);
0 Kudos
1 Solution

Accepted Solutions
KenBuja
MVP Esteemed Contributor

This works properly

Widget.html

<div>
  <div data-dojo-attach-point="sourceLayerFieldSelect"></div>
</div>

Widget.js

define(['dojo/_base/declare', 'jimu/BaseWidget', 'dijit/_WidgetsInTemplateMixin', 'jimu/dijit/Message', 'dojo/on', 'dojo/_base/lang', 'dojo/store/Memory', 'dijit/form/Select', 'esri/request', 'dojo/_base/array'], function (declare, BaseWidget, _WidgetsInTemplateMixin, Message, on, lang, Memory, Select, esriRequest, arrayUtils) {
  return declare([BaseWidget, _WidgetsInTemplateMixin], {

    // Custom widget code goes here

    baseClass: 'testing',
    _featureLayer: null,

    postCreate: function postCreate() {
      this.inherited(arguments);
      console.log('Testing::postCreate');
      this._initDijits();
    },
    _initDijits: function _initDijits() {
      var fieldNames, fieldStore, data, store, os;
      var fields = esriRequest({
        url: 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3',
        content: {
          f: "json"
        },
        callbackParamName: 'callback'
      }).then(lang.hitch(this, function (response) {
        fieldNames = { identifier: 'value', label: 'name', items: [] };
        arrayUtils.forEach(response.fields, function (f) {
          // add some field names to the FS
          fieldNames.items.push({ 'name': f.name, 'value': f.name });
        });
        data = fieldNames.items;
        store = new Memory({
          idProperty: 'name',
          data: data
        });

        var select = new Select({
          store: store,
          labelAttr: 'name',
          onChange: this._onFieldSelectChange
        }, this.sourceLayerFieldSelect);
        select.startup();
      }));
    },
    _onFieldSelectChange: function _onFieldSelectChange(value) {
      new Message({
        titleLabel: 'Field Selected',
        message: 'Selected ' + value
      });
    }
  });
});

View solution in original post

26 Replies
KenBuja
MVP Esteemed Contributor

Registry is used to look for dijits in the DOM, not an object that you've declared in code. That's what's a little confusing about the Esri sample where it uses the same name for the variable and a DOM element. If you look at the body section, you'll see there is a FilteringSelect dijit with the id "fieldNames". This is what the registry is returning.

AbhinavSharma
New Contributor III

Is there a different way to grab the fields from the object? I do use the same code in my widget.html though, i assumed that the objects should be the same if they are initiated the same way. ( I just chose to omit the var=[] because I am able to call my webmap using this.map)

0 Kudos
KenBuja
MVP Esteemed Contributor

So you have a "fieldNames" Select (or FilteringSelect) dijit in your html code? You should probably add that module into your define.

By the way, UniqueValueDefinition and ClassBreaksDefinition are not in the same order as you call the modules in define.

AbhinavSharma
New Contributor III

My widget.html is a literal rip of the sample provided :

<label for="fieldNames">Render based on: </label>
 <select id="fieldNames" name="baseSym"
 data-dojo-type="dijit/form/FilteringSelect"
 data-dojo-props="style:'width:200px;'">
 </select>

I added the module to my define but still get the same error.

I also swapped the two definitions good catch!

0 Kudos
KenBuja
MVP Esteemed Contributor

What I've done in my widget is to get the element directly using this syntax. My Select dijit is defined this way in the html:

<div data-dojo-attach-point="sourceLayerFieldSelect" class="esriCTDownloadTabTextbox" data-dojo-type="dijit/form/Select"
  data-dojo-props='required:true,trim:true,disabled:true'>
</div>

In my js code, I get and set the properties this way, using the attach-point id:

this.sourceLayerFieldSelect.set('value', selectedCategoryFieldValue);

And here is how to wire events:

this.own(on(this.sourceLayerFieldSelect, 'change', lang.hitch(this, this._onPrioritizationFieldSelectChange)));
0 Kudos
AbhinavSharma
New Contributor III

What does selectedCategoryFieldValue refer to in this case? also would the second and third snippet of code replace the entire block of code:

var canadaFields = esriRequest({
 url:"https://services7.arcgis.com/",
 content:{
 f: "json"
 },
 callbackParamName : "callback"
 });
 console.log("fields", canadaFields)
 canadaFields.then(function(resp){
 var fieldNames, fieldStore;
fieldNames = { identifier : "value", label: "name", items: []};
 console.log("fields", fieldNames)
 arrayUtils.forEach(resp.fields,function(f){
 fieldNames.items.push({"name": f.name, "value": f.name});
 console.log("fields_Sliced", fieldNames)
 });

 fieldStore = new ItemFileReadStore({ data:fieldNames});
 console.log("store", fieldStore)
 registry.byId("fieldNames").set("store", fieldStore);
 }, function(err){
 console.log("failed to get field names: ", err);
 });
 //update when field name changes
 registry.byId("fieldNames").on("change", getData);
function getData(){
 classBreaks(map.defaultFrom, map.defaultTo);
 }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
KenBuja
MVP Esteemed Contributor

selectedCategoryFieldValue is a variable that is used to set the Select dijit to a specific value.

My snippets would replace practically nothing of your code. They just show how to properly create the element and to get a reference to it. The third snippet would replace

registry.byId("fieldNames").on("change", getData);

You still have to create the store and set the dijit's store, which would be something like this:

this.fieldNames.set("store", fieldStore);

When you post code, please use the Syntax Highlighter, making the code easier to read and allow us to point to a specific line number

AbhinavSharma
New Contributor III

I went ahead and made the changes but am now getting :

ReferenceError: on is not defined‍

 from:

this.own(on(this.sourceLayerFieldSelect, 'change', lang.hitch(this, this._onPrioritizationFieldSelectChange)));

Ill attach my current code:

define(
['dojo/_base/declare',
'jimu/BaseWidget',
"esri/toolbars/draw",
"esri/toolbars/edit",
"esri/graphic",
"esri/request",
"esri/config",
"esri/tasks/ClassBreaksDefinition",
"esri/tasks/UniqueValueDefinition",
"esri/tasks/AlgorithmicColorRamp",
"esri/tasks/GenerateRendererParameters",
"esri/tasks/GenerateRendererTask",
"esri/layers/LayerDrawingOptions",
"esri/layers/FeatureLayer",
"esri/layers/Field",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/dijit/editing/TemplatePicker",
"dojo/_base/array",
"dojo/_base/event",
"dojo/_base/lang",
"dojo/parser",
"dijit/registry",
"dojo/data/ItemFileReadStore",
"dojox/grid/DataGrid",
"dijit/form/FilteringSelect",
"dijit/form/Select",
"dojo/domReady!"],
function(declare, BaseWidget, Draw, Edit, Graphic, esriRequest, esriConfig,
        ClassBreaksDefinition, UniqueValueDefinition,  AlgorithmicColorRamp,
        GenerateRendererParameters, GenerateRendererTask, LayerDrawingOptions,
        FeatureLayer,Field,
        SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol,
        TemplatePicker,
        arrayUtils, event, lang, parser, registry, ItemFileReadStore, DataGrid, FilteringSelect,select) {
  //To create a widget, you need to derive from BaseWidget.
  return declare([BaseWidget], {
    // DemoWidget code goes here

    //please note that this property is be set by the framework when widget is loaded.
    //templateString: template,

    baseClass: 'jimu-widget-ROP',

    postCreate: function() {
      this.inherited(arguments);
      console.log('postCreate');
    },

    startup: function() {
          ///INICIO/////
     parser.parse();

        // refer to "Using the Proxy Page" for more information:  https://developers.arcgis.com/javascript/3/jshelp/ags_proxy.html
        esriConfig.defaults.io.proxyUrl = "/proxy/";
          map= this.map;

        map.on("layers-add-result", initEditing);


        var landusePolygonLayer = new FeatureLayer("https://services7/ArcGIS/rest/", {
          id: "canada_Risk",//confirm works
          mode: FeatureLayer.MODE_ONDEMAND,
          outFields: ["*"]
        });
        console.log("LayerInfo", landusePolygonLayer)
       map.addLayers([landusePolygonLayer]);

       //fieldInfo
       var canadaFields = esriRequest({
         url:"https://services7.arcgis.comter/0",
         content:{
           f: "json"
         },
         callbackParamName : "callback"
       });
       console.log("fields", canadaFields)
       canadaFields.then(function(resp){
         var fieldNames, fieldStore;

         fieldNames = { identifier : "value", label: "name", items: []};
         console.log("fields", fieldNames)
         arrayUtils.forEach(resp.fields,function(f){
           fieldNames.items.push({"name": f.name, "value": f.name});
           console.log("fields_Sliced", fieldNames)
           this.sourceLayerFieldSelect.set("value", f.name)
        });

       fieldStore = new ItemFileReadStore({ data:fieldNames});
       console.log("store", fieldStore)
        //registry.byId("fieldNames").set("store", fieldStore);
        this.fieldNames.set("store", fieldStore);
        }, function(err){
        console.log("failed to get field names: ", err);
        });
        //update when field name changes
        this.own(on(this.sourceLayerFieldSelect, 'change', lang.hitch(this, this._onPrioritizationFieldSelectChange)));

        function getData(){
          classBreaks(map.defaultFrom, map.defaultTo);
        }
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
KenBuja
MVP Esteemed Contributor

You have to add a reference for "dojo/on"