I'm new to dojo and can't figure out why this is happening
in dojo.html:
require(["dojo/query", "dojo/NodeList-dom", "dojo/domReady!", "a" ], function(query, a) {
query("#greeting").style("color", "red");
alert(a.sheep);
});
in a.js
define([], function() {
var a = {
"sheep": "blah",
}
return a;
});
Requiring and loading module a is fine, but when I try to alert a.sheep, I get undefined.
Note: I've also tried declaring sheep : "blah" as well and try changing sheep to an alert function and running a.sheep; which worked.
the reason you cannot access a.sheep is that there is dojo/NodeList-dom module in a variable. The order of elements in define/require array is bind to the list of arguments in the subsequent function. So you should write:
require(["dojo/query", "a", "dojo/NodeList-dom", "dojo/domReady!"], function(query, a) {
})
Also from the practical point of view I happen to format my code like this:
define([
"dojo/_base/declare",
"dojo/query",
"a",
"dojo/NodeList-dom",
"dojo/domReady!"
],
function(
declare
query,
a
){
return declare(null, {
constructor: function() {}
});
});
Every module on his own line, plus logical clustering of modules via empty lines.
Related
I am looking for a functionality like below in dojo class (AMD).
function () {
var _foo = 123; // private variable
return {
get foo () { return _foo; }
};
}());
The advantage is once the value _foo is initialised user can't modify the value _foo or foo from the console. How do we achieve this in dojo class like
define["dojo/_base/declare", "dojo/request", "dojo/_base/lang"],
function(declare, request, lang) {
var _foo = 123;
return declare("fooClass", null, {
get foo () { return _foo; }
});
});
when i declare as above when we try to build the class using dojo build.sh it is giving parsing errors.how to make a value not changeable from debug console in dojo
There is not really an advantage with your solution, as if an user open the debugger console, a developer could set a breakpoints at var _foo =123; and change its value at run time any time.
In your code actually you are showing an example of a closure.
A closure allow your var _foo to be hidden inside your function() so a developer would not be able to get that value within its js code.
Nevertheless you can still access it using the debugger console adding a simple breakpoint.
If you are interesting to use getter and setter for dojo, please read on.
The dojo naming convention to specify a custom getter or setter (in this example for an attribute named foo) is:
_setFooAttr() and _getFooAttr()
Example:
require([
"dojo/_base/declare", "dojo/dom-style", "dojo/parser", "dojo/ready",
"dijit/_WidgetBase", "dijit/_TemplatedMixin"
], function(declare, domStyle, parser, ready, _WidgetBase, _TemplatedMixin){
declare("HidePane", [_WidgetBase], {
// parameters
open: true,
// custom setter
_setOpenAttr: function(/*Boolean*/ open){
this._set("open", open);
domStyle.set(this.domNode, "display", open ? "block" : "none");
}
});
ready(function(){
parser.parse();
});
});
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>
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.
I have built a Dojo Widget for creating a list by entering values. the widget code is:
define(["dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin", 'dojo/text!apps/orders/templates/multiAddList.html', "dojo/dom", "dojo/on", "dojo/dom-construct", "dojo/dom-class", "dojo/query", "dijit/focus"],
function (declare, WidgetBase, TemplatedMixin, html, dom, on, domConstruct, domClass, query, focusUtil) {
return declare([WidgetBase, TemplatedMixin], {
templateString: html,
postCreate: function () {
this.inherited(arguments);
var that = this;
},
_checkIfEnter: function (e) {
if (e.which == 13) {
this._addUser();
}
},
_addUser: function () {
domClass.remove(this.ulAdded, "hidden");
var textToAdd = this.userTextToAdd.value;
var li = domConstruct.create("li", {}, this.ulAdded);
domConstruct.create("span", {innerHTML: textToAdd}, li);
var spanX = domConstruct.create("span", {class: 'icon-x right'}, li);
this.itemsArray.push(textToAdd);
this.userTextToAdd.value = "";
focusUtil.focus(this.userTextToAdd);
var that = this;
on(spanX, "click", function () {
domConstruct.destroy(li);
that.itemsArray.splice(that.itemsArray.indexOf(textToAdd), 1);
if (that.itemsArray.length == 0) {
domClass.add(that.ulAdded, "hidden");
}
});
},
itemsArray: []
});
});
It is all OK. However - when I instantiate it twice on same dialog like this:
allowedDomains = new MultiAddList();
allowedDomains.placeAt(dom.byId('allowedDomains'), 0);
pdlEmails = new MultiAddList();
pdlEmails.placeAt(dom.byId('pdlEmails'), 0);
and then asking for allowedDomains.itemsArray() or pdlEmails.itemsArray() - I get the same list (as if it is the same instance) - althought in the UI presentation - he adds the list items separately and correctly.
Obviously, I am doing something wrong although I followed Dojo examples.
Does anyone know what I should do in order to make it work?
Thanks
When you make a dojo class using declare, object and array members are static, meaning they are shared across instances, so I would suggest doing itemsArray: null and then this.itemsArray = [] in the constructor or postCreate somewhere.
Everything else looks fine, although I too would have a preference for using hitch, your solution is perfectly fine.
Sorry for just giving you a hint, but you might want to look at the dojo.hicth()-function, as an alternative to the "this-that" contruction
on(spanX, "click", dojo.hitch(this, function () {
domConstruct.destroy(li);
this.itemsArray.splice(this.itemsArray.indexOf(textToAdd), 1);
if (this.itemsArray.length == 0) {
domClass.add(this.ulAdded, "hidden");
}
}));
The on-construct is a good one, but just testing this kind of construct might tell you whether that is the problem or not.
_addUser: function () {
.....
.....
dojo.connect(spanX, "click", this, this.spanClicked);
or
dojo.connect(spanX, "click", dojo.hitch(this, this.spanClicked);
},
spanClicked: function(args) {
domConstruct.destroy(li); //need to keep some reference to li
this.itemsArray.splice(this.itemsArray.indexOf(textToAdd), 1);
if (that.itemsArray.length == 0) {
domClass.add(this.ulAdded, "hidden");
}
}
Is there a way to have a static variable in a dojo (1.8) module so that I can retain state?
Example, say I set some value in some/module
require([
'some/module'
], function (module) {
module.setSomeValue(3);
});
.. and then want to retrieve it later
define([
'some/module'
], function(module) {
return {
start: function() {
var x = module.getSomeValue();
}
};
});
A solution that works but seems like a hack,
acompany = window.acompany || {};
acompany.project = acompany.project || {
};
require([
], function() {
var debug = false;
acompany.project.module = {
/* static variables and functions here */
};
});
define([
], function () {
return acompany.project.module;
});
Actually there is always only single instance of AMD module, because (source):
define has two additional important characteristics that may not be immediately obvious:
Module creation is lazy and asynchronous, and does not occur immediately when define is called. This means that factory is not executed, and any dependencies of the module will not be resolved, until some running code actually requires the module.
Once a module value has been entered into the module namespace, it is not recomputed each time it is demanded. On a practical level, this means that factory is only invoked once, and the returned value is cached and shared among all code that uses a given module. (Note: the dojo loader includes the nonstandard function require.undef, which undefines a module value.)
In addition you do not have to provide just factory function, you can provide an object literal as well:
define("some/module", {
someValue: "some",
otherValue: "other"
});
Then somewhere else in your code:
require(["some/module"], function(module) {
console.log("module.someValue", module.someValue); // some
module.someValue = "some changed";
});
require(["some/module"], function(module) {
console.log("module.someValue", module.someValue); // some changed
});
More robust solution includes an instance of dojo/Stateful, so you can watch for changes and define custom setters and getters:
define("some/stateful-module", ["dojo/Stateful"], function(Stateful){
var stateful = new Stateful({
someValue: "some",
otherValue: "other"
});
return stateful;
});
Then somewhere else in your code:
require(["some/stateful-module"], function(module) {
console.log("stateful-module.someValue:", module.get("someValue"));
module.watch(function(name, oldValue, newValue) {
console.log("stateful-module: property"
, name
, "changed from"
, "'" + oldValue + "'"
, "to"
, "'" + newValue + "'"
);
});
});
require(["some/stateful-module"], function(module) {
module.set("someValue", "some changed");
});
See how it works at jsFiddle: http://jsfiddle.net/phusick/fHvZf/. It's in a single file there, but it will work the same way across the whole application unless you require.undef(mid) the module.
There are multiple files in Dojo like dojo/date/locale that define static variables and functions and not widgets/classes using dojo.declare.
Define the module
define([
'dojo/_base/lang/',
'some/module'
], function(lang, module) {
var m = lang.getObject('some.module', true);
m.x = 0;
m.doSomething = function(){
// doSomething
};
return m;
});
Use the module
require([
'some/module'
], function(someModule) {
var debug = false;
/* someModule - static variables and functions here */
if(someModule.x == 0){
}
});