Create a new controller widget

1903
14
Jump to solution
07-28-2016 10:24 AM
WilliamMiller4
Occasional Contributor II

In an effort to better understand how Web AppBuilder works, I'm going through the samples provided under the Sample Code tab of Web AppBuilder for ArcGIS (Developer Edition)​​​. I'm working through Create a new controller widget​​, but I'm getting the following error when I reach step 5e​​: error:TypeError: this.createIconNode is not a function. Below is my code for the SidebarController\Widget.js. Any help would be appreciated. Thank you. William

define([
  'dojo/_base/declare',
  'jimu/PoolControllerMixin',
  'jimu/BaseWidget'
  ], function(
    declare,
    PoolControllerMixin,
    BaseWidget
    ) {
  //To create a widget, you need to derive from BaseWidget.
  return declare([BaseWidget, PoolControllerMixin], {
    // DemoWidget code goes here


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


    baseClass: 'jimu-widget-sidebar-controller jimu-main-background',
    
    allConfigs: [],
    
    postCreate: function() {
      this.inherited(arguments);
      console.log('postCreate');
      
      this.allConfigs = this.getAllConfigs();
      for(var i = 0; i < this.allConfigs.length; i++) {
        this._createIconNode(this.allConfigs);
      }
    },
    
    startup: function() {
      this.inherited(arguments);
      console.log('startup');
    },
    
    _createIconNode: function(iconConfig, targetNode) {
      var iconNode, iconImage;
      if(!targetNode) targetNode = this.containerNode;


      iconNode = document.createElement('DIV');
      iconNode.className = 'icon-node';
      if(iconConfig.icon) {
        iconImage = document.createElement('img');
        iconImage.src = iconConfig.icon;
      }
      if(iconConfig.label) {
        iconNode.title = iconConfig.label;
        iconImage.alt = iconConfig.label;
      }


      iconNode.appendChild(iconImage);
      targetNode.appendChild(iconNode);


      return iconNode;
    }
  });
});
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Esteemed Contributor

William,

Step 12c has some issues/typos.

it says:

_createIconNode: function(iconConfig, targetNode) {
  ...
  if (iconConfig.openAtStart) {...}
  // check if the icon is a group icon
  if(this._isGroupIcon(iconConfig)) {
    // if group's tooltip has not been created yet
    if(!this.groupTooltip[iconConfig.id]) {
      // create group tooltip and its content
     var groupTooltip = document.createElement('div');
      groupTooltip.className = 'group-tooltip';
      document.body.appendChild(groupTooltip);
      for(var i = 0; i < iconConfig.widgets.length; i++) {
        this._createIconNode(iconConfig.widgets, groupTooltip);
      }
      this.groupTooltip[iconConfig.id] = groupTooltip;
    }
  }
  ...
},

and it should be: (note line 7 and 15 are this.groupTooltips... plural not singular)

_createIconNode: function(iconConfig, targetNode) {
  ...
  if (iconConfig.openAtStart) {...}
  // check if the icon is a group icon
  if(this._isGroupIcon(iconConfig)) {
    // if group's tooltip has not been created yet
    if(!this.groupTooltips[iconConfig.id]) {
      // create group tooltip and its content
     var groupTooltip = document.createElement('div');
      groupTooltip.className = 'group-tooltip';
      document.body.appendChild(groupTooltip);
      for(var i = 0; i < iconConfig.widgets.length; i++) {
        this._createIconNode(iconConfig.widgets, groupTooltip);
      }
      this.groupTooltips[iconConfig.id] = groupTooltip;
    }
  }
  ...
},

Jianxia Song

View solution in original post

14 Replies
RobertScheitlin__GISP
MVP Esteemed Contributor

William,

  It looks like the doc has a typo. The functions name is _createIconNode so this.createIconNode is not a function in your code. But it looks like you have that corrected already in your posted code.

this._createIconNode(this.allConfigs);

Have you tried clearing your browser cache?

0 Kudos
WilliamMiller4
Occasional Contributor II

Hi Robert,

Thanks for the suggestion. After clearing my browser cache, I still had the problem. However your suggestion gave me the idea to start a new app, and now it works.

Gratefully, William

0 Kudos
WilliamMiller4
Occasional Contributor II

Now I'm having trouble with step 12 in the process. However, if I add the About widget to the SidebarController, the following warnings and error appear in the console:

    Warning: no uploadUrl provided.      FileUploader.js:32

    this.movie.PercentLoaded() failed TypeError: this.movie.PercentLoaded is not a function(…)      main.js:2867

          x 17

    Uncaught Error: Building SWF failed.      main.js:2867

Even with these errors and warning, everything seems to be working through step 11 (code below).

define([
  'dojo/_base/declare',
  'dojo/on',
  'dojo/query',
  'dojo/dom-class',
  'jimu/PoolControllerMixin',
  'jimu/BaseWidget'
  ], function(
    declare,
    on,
    query,
    domClass,
    PoolControllerMixin,
    BaseWidget
    ) {
  //To create a widget, you need to derive from BaseWidget.
  return declare([BaseWidget, PoolControllerMixin], {
    // DemoWidget code goes here
    
    //please note that this property is be set by the framework when widget is loaded.
    //templateString: template,
    
    baseClass: 'jimu-widget-sidebar-controller jimu-main-background',
    
    allConfigs: [],
    
    openedWidgetId: '',
    
    activeIconNode: null,
    
    postCreate: function() {
      this.inherited(arguments);
      console.log('postCreate');
      
      this.allConfigs = this.getAllConfigs();
      for(var i = 0; i < this.allConfigs.length; i++) {
        this._createIconNode(this.allConfigs);
      }
    },
    
    startup: function() {
      this.inherited(arguments);
      console.log('startup');
    },
    
    _createIconNode: function(iconConfig, targetNode) {
      var iconNode, iconImage;
      if(!targetNode) targetNode = this.containerNode;


      iconNode = document.createElement('DIV');
      iconNode.className = 'icon-node';
      if(iconConfig.icon) {
        iconImage = document.createElement('img');
        iconImage.src = iconConfig.icon;
      }
      
      if(iconConfig.label) {
        iconNode.title = iconConfig.label;
        iconImage.alt = iconConfig.label;
      }


      iconNode.appendChild(iconImage);
      
      targetNode.appendChild(iconNode);
      // check if the widget is set to open at start
      if (iconConfig.openAtStart) {
         // check if the icon is a group icon
        this.activeIconNode = iconNode;
        domClass.add(iconNode, 'jimu-state-active');
        this._showWidgetContent(iconConfig);
      }
      
      var self = this;
      this.own(on(iconNode, 'click', function() {
        // remove active state from any icon node
        query('.jimu-state-active', self.domNode).removeClass('jimu-state-active');
        // close panel


        // close group tooltips


        // if clicked on an active icon node
        if(self.activeIconNode === this) {
          self.panelManager.closePanel(iconConfig.id + '_panel');
          self.activeIconNode = null;
          return;
        }
        
        // show panel
        domClass.add(this, 'jimu-state-active');
        self._showWidgetContent(iconConfig);
        self.activeIconNode = this;
      }));


      return iconNode;
    },
    
    _showWidgetContent: function(iconConfig) {
      if(this.openedWidgetId) {
        this.panelManager.closePanel(this.openedWidgetId + '_panel');
      }


      var self = this;
      this.panelManager.showPanel(iconConfig).then(function(widget) {
        // the panel displays successfully
        self.own(on.once(widget, 'close', function () {
          domClass.remove(self.activeIconNode, 'jimu-state-active');
          self.activeIconNode = null;
        }));
      }, function (err) {
        // the panel failed to display
      });
      this.openedWidgetId = iconConfig.id;
    }
  });
});

After I add code for step 12 (code below), I get an error if I try to create a group (error:TypeError: Cannot read property '_29' of undefined at _createIconNode Line 79). Even if I don't create a group, the widgets will no longer close.

define([
  'dojo/_base/declare',
  'dojo/on',
  'dojo/query',
  'dojo/dom-class',
  'jimu/PoolControllerMixin',
  'jimu/BaseWidget'
  ], function(
    declare,
    on,
    query,
    domClass,
    PoolControllerMixin,
    BaseWidget
    ) {
  //To create a widget, you need to derive from BaseWidget.
  return declare([BaseWidget, PoolControllerMixin], {
    // DemoWidget code goes here
    
    //please note that this property is be set by the framework when widget is loaded.
    //templateString: template,
    
    baseClass: 'jimu-widget-sidebar-controller jimu-main-background',
    
    allConfigs: [],
    
    openedWidgetId: '',
    
    activeIconNode: null,
    
    groupTooltips: {},
    
    
    postCreate: function() {
      this.inherited(arguments);
      console.log('postCreate');
      
      this.allConfigs = this.getAllConfigs();
      for(var i = 0; i < this.allConfigs.length; i++) {
        this._createIconNode(this.allConfigs);
      }
    },
    
    startup: function() {
      this.inherited(arguments);
      console.log('startup');
    },
    
    _createIconNode: function(iconConfig, targetNode) {
      var iconNode, iconImage;
      if(!targetNode) targetNode = this.containerNode;


      iconNode = document.createElement('DIV');
      iconNode.className = 'icon-node';
      if(iconConfig.icon) {
        iconImage = document.createElement('img');
        iconImage.src = iconConfig.icon;
      }
      
      if(iconConfig.label) {
        iconNode.title = iconConfig.label;
        iconImage.alt = iconConfig.label;
      }


      iconNode.appendChild(iconImage);
      
      targetNode.appendChild(iconNode);
      // check if the widget is set to open at start
      if (iconConfig.openAtStart) {
         // check if the icon is a group icon
        this.activeIconNode = iconNode;
        domClass.add(iconNode, 'jimu-state-active');
        this._showWidgetContent(iconConfig);
      }
      
      // check if the icon is a group icon
      if(this._isGroupIcon(iconConfig)) {
        // if group's tooltip has not been created yet
        if(!this.groupTooltip[iconConfig.id]) {
          // create group tooltip and its content
         var groupTooltip = document.createElement('div');
          groupTooltip.className = 'group-tooltip';
          document.body.appendChild(groupTooltip);
          for(var i = 0; i < iconConfig.widgets.length; i++) {
            this._createIconNode(iconConfig.widgets, groupTooltip);
          }
          this.groupTooltip[iconConfig.id] = groupTooltip;
        }
      }
      
      var self = this;
      this.own(on(iconNode, 'click', function() {
        // remove active state from any icon node
        query('.jimu-state-active', self.domNode).removeClass('jimu-state-active');
        // close panel
        self.panelManager.closePanel(self.openedWidgetId + '_panel');
        // close group tooltips
        query('.group-tooltip').removeClass('show');
        // if clicked on an active icon node
        if(self.activeIconNode === this) {
          self.activeIconNode = null;
          return;
        }
        // clicking on a group icon
        if (self._isGroupIcon(iconConfig)) {
          self.openedWidgetId = null;
          self._positionTooltip(self.groupTooltips[iconConfig.id], this);
          domClass.add(self.groupTooltips[iconConfig.id], 'show');
        } else { // clicking on a widget icon
          // show panel
          self._showWidgetContent(iconConfig);
        }
          domClass.add(this, 'jimu-state-active');
          self.activeIconNode = this;
      }));


      return iconNode;
    },
    
    _showWidgetContent: function(iconConfig) {
      if(this.openedWidgetId) {
        this.panelManager.closePanel(this.openedWidgetId + '_panel');
      }


      var self = this;
      this.panelManager.showPanel(iconConfig).then(function(widget) {
        // the panel displays successfully
        self.own(on.once(widget, 'close', function () {
          domClass.remove(self.activeIconNode, 'jimu-state-active');
          self.activeIconNode = null;
        }));
      }, function (err) {
        // the panel failed to display
      });
      this.openedWidgetId = iconConfig.id;
    },
    
    _isGroupIcon: function(iconConfig) {
      return iconConfig.widgets && iconConfig.widgets.length > 1;
    },
    
    _positionTooltip: function(tooltip, iconNode) {
      var iconBoundingRect = iconNode.getBoundingClientRect();
      tooltip.style.top = iconBoundingRect.top + 'px';
      tooltip.style.left = (iconBoundingRect.width || iconNode.clientWidth) + 'px';
    }
  });
});

Thank you for your time and help.

William

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

William,

Step 12c has some issues/typos.

it says:

_createIconNode: function(iconConfig, targetNode) {
  ...
  if (iconConfig.openAtStart) {...}
  // check if the icon is a group icon
  if(this._isGroupIcon(iconConfig)) {
    // if group's tooltip has not been created yet
    if(!this.groupTooltip[iconConfig.id]) {
      // create group tooltip and its content
     var groupTooltip = document.createElement('div');
      groupTooltip.className = 'group-tooltip';
      document.body.appendChild(groupTooltip);
      for(var i = 0; i < iconConfig.widgets.length; i++) {
        this._createIconNode(iconConfig.widgets, groupTooltip);
      }
      this.groupTooltip[iconConfig.id] = groupTooltip;
    }
  }
  ...
},

and it should be: (note line 7 and 15 are this.groupTooltips... plural not singular)

_createIconNode: function(iconConfig, targetNode) {
  ...
  if (iconConfig.openAtStart) {...}
  // check if the icon is a group icon
  if(this._isGroupIcon(iconConfig)) {
    // if group's tooltip has not been created yet
    if(!this.groupTooltips[iconConfig.id]) {
      // create group tooltip and its content
     var groupTooltip = document.createElement('div');
      groupTooltip.className = 'group-tooltip';
      document.body.appendChild(groupTooltip);
      for(var i = 0; i < iconConfig.widgets.length; i++) {
        this._createIconNode(iconConfig.widgets, groupTooltip);
      }
      this.groupTooltips[iconConfig.id] = groupTooltip;
    }
  }
  ...
},

Jianxia Song

WilliamMiller4
Occasional Contributor II

Hi Robert,

Thanks for your help with the groupTooltips issue. That part is working. Unfortunately, while the group widget "closes", the solo widgets stay visible after a second click (the first click for opening them). The following snippet shows where I think the issue might be located in the code.

this.own(on(iconNode, 'click', function() {
  // remove active state from any icon node
  query('.jimu-state-active', self.domNode).removeClass('jimu-state-active');
  // close panel
////self.panelManager.closePanel(self.openedWidgetId + '_panel');            // uncomment this line and the group widget closes
  // close group tooltips
  query('.group-tooltip').removeClass('show');

  // if clicked on an active icon node
  if(self.activeIconNode === this) {
//////self.panelManager.closePanel(iconConfig.id + '_panel');               // uncomment this line and the solo widgets close
    self.activeIconNode = null;
    return;
  }

Uncomment both lines 5 and 11 and only the group widget "closes."

Again, any help would be greatly appreciated.

William

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

William,

  Here is my complete _createIconNode function that is working fine for me:

_createIconNode: function(iconConfig, targetNode) {
      var iconNode, iconImage;
      if(!targetNode) targetNode = this.containerNode;

      iconNode = document.createElement('DIV');
      iconNode.className = 'icon-node';
      if(iconConfig.icon) {
        iconImage = document.createElement('img');
        iconImage.src = iconConfig.icon;
      }

      if(iconConfig.label) {
        iconNode.title = iconConfig.label;
        iconImage.alt = iconConfig.label;
      }

      iconNode.appendChild(iconImage);

      targetNode.appendChild(iconNode);
      // check if the widget is set to open at start
      if (iconConfig.openAtStart) {
         // check if the icon is a group icon
        this.activeIconNode = iconNode;
        domClass.add(iconNode, 'jimu-state-active');
        this._showWidgetContent(iconConfig);
      }

      // check if the icon is a group icon
      if(this._isGroupIcon(iconConfig)) {
        // if group's tooltip has not been created yet
        if(!this.groupTooltips[iconConfig.id]) {
          // create group tooltip and its content
         var groupTooltip = document.createElement('div');
          groupTooltip.className = 'group-tooltip';
          document.body.appendChild(groupTooltip);
          for(var i = 0; i < iconConfig.widgets.length; i++) {
            this._createIconNode(iconConfig.widgets, groupTooltip);
          }
          this.groupTooltips[iconConfig.id] = groupTooltip;
        }
      }

      var self = this;
      this.own(on(iconNode, 'click', function() {
        // remove active state from any icon node
        query('.jimu-state-active', self.domNode).removeClass('jimu-state-active');
        // close panel
        self.panelManager.closePanel(self.openedWidgetId + '_panel');
        // close group tooltips
        query('.group-tooltip').removeClass('show');
        // if clicked on an active icon node
        if(self.activeIconNode === this) {
          self.activeIconNode = null;
          return;
        }
        // clicking on a group icon
        if (self._isGroupIcon(iconConfig)) {
          self.openedWidgetId = null;
          self._positionTooltip(self.groupTooltips[iconConfig.id], this);
          domClass.add(self.groupTooltips[iconConfig.id], 'show');
        } else { // clicking on a widget icon
          // show panel
          self._showWidgetContent(iconConfig);
        }
          domClass.add(this, 'jimu-state-active');
          self.activeIconNode = this;
      }));
      return iconNode;
    },

    _showWidgetContent: function(iconConfig) {
      if(this.openedWidgetId) {
        this.panelManager.closePanel(this.openedWidgetId + '_panel');
      }

      var self = this;
      this.panelManager.showPanel(iconConfig).then(function(widget) {
        // the panel displays successfully
        self.own(on.once(widget, 'close', function () {
          domClass.remove(self.activeIconNode, 'jimu-state-active');
          self.activeIconNode = null;
        }));
      }, function (err) {
        // the panel failed to display
      });
      this.openedWidgetId = iconConfig.id;
    },
0 Kudos
WilliamMiller4
Occasional Contributor II

Hi Robert,

The code is are the same...

Are your panels Simple Border Panels:                                  Or Foldable(?) Panels:

SimpleBorderPanel.jpgDefaultPanel.jpg

I'm having trouble with the Simple Border Panels.

Does it matter that I'm using Web AppBuilder 2.0 and not 2.1?

Thanks again and sorry to be such a bother.

William

0 Kudos
Jianxia
Esri Regular Contributor

Robert-- Thanks for the correction. The code update will be applied in the mid of August.

Jianxia

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

William,

  I was using foldable panels. Did I miss some step about the simple border panels?

0 Kudos