Dojo FAQ: Does Dojo support directives like Angular?

By on June 11, 2014 12:00 pm

DojoFAQ

Most JavaScript frameworks have a mechanism for building reusable UI components that can be instantiated in your application. In AngularJS the reusable UI component is known as a directive. When you define a directive, you are creating a reusable UI component within your application. Angular allows you to declaratively use a directive in your HTML markup.

Dojo has a similar mechanism for creating reusable UI components called Dijits. Dijits can also be used declaratively in HTML and the Dojo parser will instantiate the Dijit for you.

Comparing a directive written in AngularJS and the same component written as a Dojo Dijit side by side will help illustrate how you can get the same functionality from a Dojo Dijit that you would get with an Angular directive.

The example component for this blog post is a kitten slide show. You define the slide show in your HTML markup and pass in the number of slides the slide show should render and the amount of delay between the slides. If you are interested, you can experiment with the Angular and Dojo examples on JSFiddle.

Angular directive

The HTML markup for the Angular directive is simple. Create a kitten-show HTML element with the attributes kt-slides and kt-delay. The kt-slides attribute allows you to define the number of slides displayed by the slide show. The kt-delay attribute defines the amount of time, in seconds, to pause between slides.

<div ng-app="meow">
    <h1>Show Time</h1>
    <kitten-show kt-slides="5" kt-delay="3"></kitten-show>
</div>

In our JavaScript code, we setup a directive that will replace the kittenShow element with the HTML element defined by the directive’s template. In our link function, we parse the ktSlides and ktDelay attributes and generate the data required to render our slide images. We then setup an interval that will rotate through our images using the configured delay period.

 var module = angular.module('meow', []);

// define the kitten show directive
module.directive('kittenShow', function() {
	return {
		// define the kittenShow element
		restrict: 'E',
		// replace the element with our template
		replace: true,
		template: '<div class="frame"><div class="image"><strong>kitten {{name}}</strong><img src="http://placekitten.com/{{width}}/{{height}}"></div></div>',
		link: function(scope, ele, attrs){
			// parse attribute values
			var slideCount = parseInt(attrs.ktSlides, 10) || 4;
			var delay = parseInt(attrs.ktDelay, 10) || 3;
			var sizes = generateImageSizes(slideCount);
			var currentSlide = 0;
			
			function rotateImage() {
				currentSlide = ++currentSlide >= sizes.length ? 0 : currentSlide;
				scope.width = sizes[currentSlide].width;
				scope.height = sizes[currentSlide].height;
				scope.name = currentSlide;
			}
			
			rotateImage();
			
			setInterval(function() {
				// notify angular of a scope change
				scope.$apply(rotateImage);
			}, delay*1000);
			
		}
	};
});    

Dojo Dijit

Now we are going to create the same component as we did in the Angular example, but using the Dojo parser to parse our HTML and instantiate our Dijit.

The HTML markup for the Dijit is slightly different from the Angular version. In the Dijit version instead of using a custom HTML element tag for our widget, we use the data-dojo-type attribute to specify which widget should be used. To pass in the required number of slides and the delay period, we use the data-dojo-props attribute which will set the initial values for the number of slides and the delay period.

<h1>Show Time</h1>
<div data-dojo-type="kittenShow"
     data-dojo-props="slideCount: 5, delayTime: 3"></div>

In the JavaScript code, we declare our kittenShow Dijit. In order to leverage the Dojo parser, we need to extend from WidgetBase, and use the TemplatedMixin. This allows us to specify a template to use as well as attach points in the template that we can then use to update the UI. In Dijit an attach point allows us to specify which DOM nodes we have a reference to in our Dijit JavaScript code.

We want to define a startup function so we can generate our data based on the widget settings and then start the slideshow like we did in the Angular example.

require(['dojo/parser', 'dojo/_base/lang', 'dojo/_base/declare', 'dijit/_WidgetBase', 'dijit/_TemplatedMixin', 'dojo/domReady!'
], function(parser, lang, declare,  _WidgetBase, TemplatedMixin) {

    // Normally you would declare a constructor starting with an uppercase letter. In this example we 
    // are using lowercase to match the angular style for directive declaration.
    // Also, with Dojo we would normally place this in a separate module and not create a global kittenShow
    // variable, but again, this is for making the comparison easier to understand.
    declare('kittenShow', [_WidgetBase, _TemplatedMixin], {
        slideCount: 0,
        delayTime: 0,
        _currentSlide: 0,
        _imageSizes: [],
        templateString: '<div class="frame"><div class="image"><strong data-dojo-attach-point="titleEle"></strong><img data-dojo-attach-point="imgEle"></div></div>',
        startup: function() {
            this._imageSizes = generateImageSizes(this.slideCount);
            this._updateShow();
            setInterval(lang.hitch(this, '_updateShow'), this.delayTime * 1000);
        },
        _updateShow: function() {
            var size;
            this._currentSlide = ++this._currentSlide >= this._imageSizes.length ? 0 : this._currentSlide;
            size = this._imageSizes[this._currentSlide];
            this.titleEle.innerHTML = 'kitten '+ this._currentSlide;
            this.imgEle.src = 'http://placekitten.com/'+size.width+'/'+size.height;
        }
    });
    
    parser.parse();
});

Conclusion

Using declarative HTML markup to instantiate Dijits is a bit different than defining a directive in Angular, but the results are similar. We can define widgets declaratively in our markup and the framework will render the widgets for us.

To learn more about the Dojo parser, review the parser documentation. You can learn more about authoring Dijits by reading the custom widget tutorial. On a related note, we also recently published a blog post on the topic of creating widgets with inline templates.

Learning more

We cover Dijit and custom widget development more in depth in our Dojo workshops offered throughout the US, Canada, and Europe, or at your location. We also provide expert JavaScript and Dojo support and development services, to help you get the most from JavaScript, Dojo, and Angular.

Comments

  • Manachi

    Really good article. My background is in Dojo, but I’ve recently been experimenting with some Angular, and this article gives a good, clear & helpful comparison of two key features. Thanks!