startup is not getting called for Dojo Custom Widget - dojo

I created a Custom Widget in Dojo
return declare("DrawTools", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
templateString: template,
layers: [],
constructor: function (featureLayerArr) {
},
postCreate: function () {
},
startup: function () {
var menu = new DropDownMenu({ style: "display: none;" });
var menuItem1 = new MenuItem({
label: "Save",
iconClass: "dijitEditorIcon dijitEditorIconSave",
onClick: function () { alert('save'); }
});
menu.addChild(menuItem1);
var menuItem2 = new MenuItem({
label: "Cut",
iconClass: "dijitEditorIcon dijitEditorIconCut",
onClick: function () { alert('cut'); }
});
menu.addChild(menuItem2);
menu.startup();
var button = new DropDownButton({
label: "hello!",
name: "programmatic2",
dropDown: menu,
id: "progButton"
}, this.drawToolsMenuNode).startup();
},
startMenu: function () {
}
});
Wdiget template is as follows
<div>
<div data-dojo-attach-point="drawToolsMenuNode"></div>
</div>
I am instantiating Widget in another Custom Widget as follows
var drawTools = new DrawTools(this.allLayersArr);
drawTools.placeAt(this.drawToolsNode);
drawTools.startMenu();
startup method for DrawTools widget is not getting called.
Need help in this regard.

Offical definition from dojo
startup():
Probably the second-most important method in the Dijit lifecycle is the startup method. This method is designed to handle processing after any DOM fragments have been actually added to the document; it is not fired until after any potential child widgets have been created and started as well. This is especially useful for composite widgets and layout widgets.
When instantiating a widget programmatically, always call the widget's startup() method after placing it in the document. It's a common error to create widgets programmatically and then forget to call startup, leaving you scratching your head as to why your widget isn't showing up properly.
So as Kirill mentioned, you need to call the startup method.

The alternative solution would be moving widget instantiation logic from ::startup() to ::postCreate(), since ::postCreate() will be called for sure.

Related

trying to derive from a dijit Button: "TypeError: this._attachEvents is undefined"

I am trying to derive an "extended" Button from dijit/Form/Button. (I want to pass extra arguments to the constructor, and I want to encapsulate these preparations in my derived class. Button is just an example, I want to use this later with grids and trees.)
Unfortunately the code below fails with "TypeError: this._attachEvents is undefined" in the firefox javascript console. Some idea, what is wrong? The same code, including minimal HTML, is ready to run at http://jsfiddle.net/x9dLs8gz/1/
require(["dojo/_base/declare", "dijit/form/Button", "dojo/dom", "dojo/json", "dojo/domReady!"],
function (declare, Button, dom, json) {
declare("MyButton", Button, {
"-chains-": {
constructor: "manual"
},
constructor: function () {
//extra calculation will go here...
this.inherited(arguments);
}
});
new MyButton({
label: "Click Me!",
onClick: function () {
dom.byId("result").innerHTML += "Success";
}
}, "button").startup();
});
Cheers,
Dominic
If the "-chains-" value for the constructor method is either not set or set to "after", then the postscript method will be called after all of the inherited constructors have been fired. On the other hand, when specifying "manual", postscript is fired after the first constructor (in this case MyButton#constructor) is executed. As a result, _AttachMixins#buildRendering is fired before this._attachEvents has been set in _AttachMixins#constructor, causing the error you see.
Since specifying "manual" means that no chaining is assumed whatsoever, mixin contructors will never be called, even if this.inherited is correctly called up the chain. This makes sense, as the underlying C3MRO is thrown out the window.
If you need to continue using the "manual" setting in spite of this, you will need to 1) recreate any missing data yourself, 2) manually call the mixin constructors (e.g., _AttachMixin.prototype.constructor.call(this)), or 3) convert MyButton to a factory for Button:
var createButton = (function () {
var myButtonDefaults = { ... };
return function (kwArgs, id) {
var buttonId = id || 'button';
return new Button(lang.mixin({}, myButtonDefaults, kwArgs), buttonId);
};
})();
var myButton = createButton();
myButton.startup();
console.log(myButton instanceof Button); // true
You need to assign the declared class to a variable or declare in a different file and added it to the list of object in the require. Also dont use variable names which are keywords like "constructor". below is the fixed version of your example.
require(["dojo/_base/declare", "dijit/form/Button", "dojo/dom", "dojo/json", "dojo/domReady!"],
function(declare, Button, dom, json) {
var MyButton = declare("MyButton", Button, {
"-chains-": {
constructorType: "manual"
},
constructor: function() {
//extra calculation will go here...
this.inherited(arguments);
}
});
new MyButton({
label: "Click Me!",
onClick: function() {
dom.byId("result1").innerHTML += "Success";
}
}, "button").startup();
});
<div id="button"></div>
<div id="result1"></div>

Widgets inside Dojo dgrid OnDemandList

I'm trying to do something similar to this question but using an OnDemandList instead of an OnDemandGrid.
Here is what I have so far
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dgrid/OnDemandList",
"widget/CategoryItem",
"dojo/dom-construct",
"dojo/text!./templates/category-list.html"
], function(declare, _Widget, _TemplatedMixin, _WidgetsInTemplateMixin, OnDemandList, CategoryItem, domConstruct, template) {
var CatList = declare([OnDemandList]);
return declare([_Widget, _TemplatedMixin, _WidgetsInTemplateMixin], {
templateString: template,
baseClass: "category-list",
postCreate: function() {
this.inherited(arguments);
// Create OnDemandList, place in div defined in template.
var cat1 = this.cat1 = new CatList({
store: this.store,
renderRow: this.renderItem
}, this.categoriesLevel0);
},
renderItem: function(item) {
return new CategoryItem({
title: item.title
});
}
});
});
The problem is my renderItems function needs to somehow return a dom containing my custom widget. As it is now I get this error Error on domReady callback: Error: NotFoundError: DOM Exception 8
Yeah it definitely needs to return a dom node from renderRow. Assuming you're using _WidgetBase for CategoryItem it should work like:
renderItem: function(item) {
var category = new CategoryItem({
title: item.title
});
return category.domNode;
}
The example here: https://github.com/SitePen/dgrid/wiki/OnDemandList-and-OnDemandGrid does pretty much the same thing, except it uses put-selector, which is just constructing a div, attaching the widget to it and returning the new div.

dojo custom widget is not working

I have following Java script class for custom widget. But it is not working. Non of the functions are called. Kindly help, not able to proceed further.
dojo.provide("FancyCounter");
dojo.require("dijit._Widget");
dojo.require("dojo.parser");
dojo.declare("FancyCounter",[dijit._Widget],
{
//counter
_i:0,
buildRendering: function()
{
//create DOM
this.domNode = dojo.create("button",{innerHTML:this._i});
},
postCreate: function()
{
this.connect(this.domNode,"onClick","increment");
},
increment:function()
{
//you need to update dom in order to refresh display i believe
this.domNode.innerHTML = ++this._i;
},
});
dojo.ready(function(){
dojo.parser.parse();
});
/////html code
<span data-dojo-type ="FancyCounter"></span>
Change
this.connect(this.domNode,"onClick","increment");
To
this.connect(this.domNode,"onclick","increment");
With lowercase 'c'. Youre connecting to an event on a DOM node, see http://www.w3schools.com/jsref/dom_obj_event.asp

Constrain position of Dojo FloatingPane

I have a dojox.layout.FloatingPane (as a custom dijit) which can be positioned anywhere within its enclosing div. My problem is that the user can potentially drag the FloatingPane completely outside of its container and be unable to retrieve it. Is there any easy way to force the FloatingPane to remain entirely visible at all times?
Here's my code:
dojo.provide("ne.trim.dijits.SearchDialog");
dojo.require("dijit._Widget");
dojo.require("dijit._Templated");
dojo.require("dojox.layout.FloatingPane");
dojo.declare("ne.trim.dijits.SearchDialog", [dijit._Widget, dijit._Templated], {
templateString: dojo.cache("ne.trim.dijits", "templates/SearchDialog.html"),
initialised:false,
floatingPane: null,
postCreate: function() {
this.init();
},
init: function() {
console.debug("SearchDialog.init()", "start");
if ( this.initialised === false ) {
this.createSearchDialog();
}
//ne.trim.AppGlobals.searchDialog = this;
console.debug("SearchDialog.init()", "end");
},
createSearchDialog: function() {
var node = dojo.byId('searchbox');
floatingPane = new dojox.layout.FloatingPane({
title: "A floating pane",
resizable: true, dockable: true, constrainToContainer: true,
style: "position:absolute;top:100;right:100;width:400px;height:300px;z-index:100",
}, node );
this.initialised=true;
floatingPane.startup();
}
});
First of all, see the working example at jsFiddle: http://jsfiddle.net/phusick/3vTXW/
And now some explanation;) The DnD functionality of FloatingPane is achieved via dojo.dnd.Moveable class instantialized in pane's postCreate method. To constrain the movement of the FloatingPane you should use one of these moveables instead:
dojo.dnd.parentConstainedMoveable - to constrain by a DOM node
dojo.dnd.boxConstrainedMoveable - to constrain by co-ordinates: {l: 10, t: 10, w: 100, h: 100}
dojo.dnd.constrainedMoveable - to constrain by co-ordinates calculated in a provided function
For more details see aforementioned jsFiddle.
According to documentation you should call destroy() on Moveable instance to remove it, but as FloatingPane's original Moveable is not assigned to any object property, I do not destroy it, I just instantiate one of those three moveables on the same DOM node in a subclass:
var ConstrainedFloatingPane = dojo.declare(dojox.layout.FloatingPane, {
postCreate: function() {
this.inherited(arguments);
this.moveable = new dojo.dnd.move.constrainedMoveable(this.domNode, {
handle: this.focusNode,
constraints: function() {
return dojo.coords(dojo.body());
}
});
}
});
Now you can use ConstainedFloatingPane instead of dojox.layout.FloatingPane:
var floatingPane = new ConstrainedFloatingPane({
title: "A Constrained Floating Pane",
resizable: true
}, searchboxNode);

Dojo Exception on hiding a dijit.Dialog

I have a Dialog with a form inside. The following code is just an example of what I'm trying to do. When you close a dijit.Dialog, if you dont't destroy recursively his children, you just can't reopen it (with the same id).
If you don't want to destroy your widget you can do something like that :
var createDialog = function(){
try{
// try to show the hidden dialog
var dlg = dijit.byId('yourDialogId');
dlg.show();
} catch (err) {
// create the dialog
var btnClose = new dijit.form.Button({
label:'Close',
onClick: function(){
dialog.hide();
}
}, document.createElement("button"));
var dialog = new dijit.Dialog({
id:'yourDialogId',
title:'yourTitle',
content:btnClose
});
dialog.show();
}
}
I hope this can help but with this code the error thrown is :
exception in animation handler for: onEnd (_base/fx.js:153)
Type Error: Cannot call method 'callback' of undefined (_base/fx.js:154)
I have to say I'm a little lost with this one ! It is driving me crazy ^^
PS : sorry for my "French" English ^^
I'll introduce you to your new best friend: dojo.hitch()
This allows you to bind your onClick function to the context in which it was created. Chances are, when you push the button in your code, it is calling your .show() .hide() form the context of the global window. var dlg was bound to your createDialog function, so it's insides are not visible to the global window, so the global window sees this as undefined.
Here's an example of what I changed to your code:
var createDialog = function(){
// try to show the hidden dialog
var dlg = dijit.byId('yourDialogId');
dlg.show();
// create the dialog
var btnClose = new dijit.form.Button({
label:'Close',
onClick: function(){
dojo.hitch(this, dlg.hide());
}
}, document.createElement("button"));
dlg.domNode.appendChild(btnClose.domNode);
var btnShow = new dijit.form.Button({
label : 'Open',
onClick : function() {
dojo.hitch(this, dlg.show());
}
}, document.createElement("Button"));
dojo.body().appendChild(btnShow.domNode);
};
dojo.ready(function() {
createDialog();
});
Note the use of dojo.hitch() to bind any future calls or clicks of the various buttons to the context in which the dlg was created, forever granting the button's onclick method access to the inside of the createDialog function, where var dlg exists.
hi if i understand correctly, you didn't need to destroy dijit.Dialog every time. E.g.:
HTML: define simple button:
<button id="buttonTwo" dojotype="dijit.form.Button" onclick="showDialog();" type="button">
Show me!
</button>
Javascript:
// required 'namespaces'
dojo.require("dijit.form.Button");
dojo.require("dijit.Dialog");
// creating dialog
var secondDlg;
dojo.addOnLoad(function () {
// define dialog content
var content = new dijit.form.Button({
label: 'close',
onClick: function () {
dijit.byId('formDialog').hide();
}
});
// create the dialog:
secondDlg = new dijit.Dialog({
id: 'formDialog',
title: "Programatic Dialog Creation",
style: "width: 300px",
content: content
});
});
function showDialog() {
secondDlg.show();
}
See Example and reed about dijit.dialog