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; } }); });
Solved! Go to Solution.
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; } } ... },
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?
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
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
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; } } ... },
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
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; },
Hi Robert,
The code is are the same...
Are your panels Simple Border Panels: Or Foldable(?) Panels:
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
Robert-- Thanks for the correction. The code update will be applied in the mid of August.
Jianxia
William,
I was using foldable panels. Did I miss some step about the simple border panels?