The Dojo Toolkit is both the most powerful and least used JavaScript framework.
Dojo consists of
AMD modules, most of which are widgets. Widgets usually consist of logic in a javascript and html template. In future version 2.0,
WebComponents support is
announced .
Dojo makes it easy to create a completely new widget or expand or modify an existing one. In this post I will tell you how to do it.
Creating a simple widget
First, create a simple widget.
Step 1: Creating the structure
To advertise your widget, you need to create a JavaScript file with the following content:
define([ "dojo/_base/declare", "dijit/_Widget", "dijit/_TemplatedMixin" ], function(declare, _Widget, _TemplatedMixin){ return declare([_Widget, _TemplatedMixin], {}); });
So far we just declared the
AMD module and indicated several dependencies. The first argument to the
declare function is an array of modules from which you want to inherit the generated module. Now it is stated that the module inherits the
dijit / _Widget module, which is basic for all widgets,
and the _TemplatedMixin module, which is provided by the template engine.
Step 2: Creating an HTML View
Create a templates folder next to the module file and an HTML file in it. It is better to call it as well as the module file. Let the module be called MyCustomWidget.js, then the template file should be called MyCustomWidget.html. The template file should contain the HTML representation of the widget. And the root must be one.
')
The template engine allows you to:
- specify special nodes, attachPoints , which will be available as widget properties;
To do this, you need to set a special attribute for the desired node: data-dojo-attach-point = ”customNode” , where “customNode” is the name of the widget property through which the node will be available. The root node of the widget is always accessible via the domNode property.
- define event handlers;
To do this, you need to set a special attribute for the required node: data-dojo-attach-event = ”ondijitclick: _onClick” , where “ondijitclick” indicates the event to be processed, in this case click, and “_onClick” is the name of the method that should act as an event handler.
- specify the place where the values ​​of the widget's properties are substituted during its creation.
To do this, in the template you need to write $ {nameProp} , where “nameProp” is the name of the property.
Step 3: Link the template and data
Connect the template:
define([ "dojo/_base/declare", "dijit/_Widget", "dijit/_TemplatedMixin", "dojo/text!./templates/MyCustomWidget.html" ], function(declare, _Widget, _TemplatedMixin, template){ return declare([_Widget, _TemplatedMixin], { templateString: template }); });
In fact, we could not make the template into a separate file, but immediately set HTML as the value of the
templateString property or put it into a variable, but, in my opinion, this reduces the beauty of the code.
As an example widget, create a widget that displays the last name and first name.
<div> <span data-dojo-attach-point="surnameNode">${surname}</span> <span data-dojo-attach-point="nameNode">${name}</span> </div>
In order for each time the widget's properties change, the values ​​change in HTML, you must associate property setters and
attachPoints . You can specify which property of which
attachPoint corresponds to which property of the widget, or you can define your own setters.
If you have a property where setting / getting a value is more difficult than just referring to the property of an object, then you need to define your own setters / getters following simple naming rules: for the “foo” property, these will be
_setFooAttr / _getFooAttr . The
set and
get methods will automatically find them and call them if necessary.
define([ "dojo/_base/declare", "dijit/_Widget", "dijit/_TemplatedMixin", "dojo/text!./templates/MyCustomWidget.html" ], function(declare, _Widget, _TemplatedMixin, template){ return declare([_Widget, _TemplatedMixin], { templateString: template, _setSurnameAttr: { node: "surnameNode", type: "innerHTML" }, _setNameAttr: function(val){ this.nameNode.innerHTML = val; this._set("name", val); } }); });
As you, probably, could already guess, the described widget can be connected using its name and location. You can use the direct path to the JS-file of the module, or you can declare your package, by analogy with dojo, dijit and dojox, and include files from it. An alternative is to immediately use the result of calling the
declare function.
How the code created by us can be viewed
here .
Widget consisting of other widgets
The widget may consist of other widgets. Component widgets can be added dynamically during the creation of the widget, but it is more convenient to declare them immediately in the template. For this, modules from which the widget is inherited must add
dijit / _WidgetsInTemplateMixin .
As an example of a template, consider a fragment of a slider template, which consists of a horizontal slider and an input text field:
<div> <div> <div data-dojo-type="dijit/form/HorizontalSlider" data-dojo-attach-point="slider" name="${name}" value="${value}" maximum="${maximum}" minimum="${minimum}" step="${step}" showButtons="${showButtons}" intermediateChanges="${intermediateChanges}" style="width:150px"> </div> <div data-dojo-type="dijit/form/TextBox" value="${value}" type="number" data-dojo-attach-point="textbox"> </div> <span data-dojo-attach-point="legendNode"></span> </div> <div data-dojo-attach-point="descriptionNode"></div> </div>
In this snippet, we declared the
dijit / form / HorizontalSlider widget, which is a horizontal slider, and the
dijit / form / TextBox widget is a text input box.
All widgets are immediately entered into a special markup and have:
- properties with fixed values;
- properties whose values ​​are forwarded from the slider widget.
Also, we supplied nested widgets with
data-dojo-attach-point attributes so that they can be accessed as properties of the widget. Those. if we want to get the value of the input field, we need to write:
this.textbox.get("value");
A similar widget from
APS JS SDK can be seen in
APS Fiddle .
Widget life cycle
The life cycle of the widget allows you to understand what is happening and when.

You can extend or override the following methods:
- constructor
Your constructor method will be called before the creation parameters are mixed with the default value of the properties, and can be used, for example, to initialize arrays.
- widget creation options are mixed with default property values
This action cannot be overridden, but it is important to know when this happens.
- postMixInProperties
This method is called before the HTML representation of the widget is created. If you need to add or change the properties of an instance of a widget before creating its visual presentation, this is the best place to do this.
- buildRendering
dijit / _Templated provides the implementation of buildRendering , which is sufficient in most cases: it will load and read the template, create DOMElements, attach special nodes and events. The final result will be placed in this.domNode . If you are not using dijit / _Templated , for example, you use another template engine, then this is the place where you should use it.
- setters are called
Setters are called for properties whose values ​​were set at widget instance creation or are not empty by default.
- postCreate
The main place for additional logic when creating a widget. But remember, in the case of a container widget, the child (not the ones declared in the template) widgets have not been added yet and the HTML representation has not yet been placed in the DOM.
- startup
Analysis and creation of all child widgets is completed. Widget placed in DOM.
- destroy
Implement destroy if you need to perform any additional actions when destroying the widget.
Inherited
When redefining a method, it is always useful to make sure that you have not lost something important that happens in this method up the inheritance chain. So do not forget to call
this.inherited before or after your code.
postCreate: function(){
useful links
Another example of creating a widget .
More information on creating widgets.More information about the widget's life cycle.