HTML5 data-dojo Attribute Support

By on January 19, 2012 9:05 am

Dojo has long provided support for declaring widgets and specifying other information directly in HTML. This support makes it extremely quick and easy to get an application started. You can start instantiating widgets by adding attributes to HTML elements before even writing any code. This is not only a very convenient tool, but using a declarative approach to binding widgets to elements can be viewed as cleaner and more organized than using the imperative mechanics of JavaScript.HTML5 Powered with Semantics Widgets declared in markup have an encapsulated construction, avoiding instantiation that requires spanning and synchronizing HTML and code manually.

However, the use of Dojo’s declarative tools has been avoided by some because it uses custom attributes that are outside the HTML specification. While this approach works in every browser on the market and is implicitly allowed, it does not validate against the HTML4 validators. Now, the new HTML5 specification provides a namespace for custom attributes. The data-* attributes are available for libraries and authors to use for their own purposes and extensions while still having validating markup. The HTML5 specification further recommends that library use a sub-namespace for their custom attributes to avoid conflicts with other code. All of the Dojo custom attributes begin with data-dojo-. Let’s look at the new Dojo attributes.

data-dojo-config

The data-dojo-config attribute replaces the djConfig attribute on the dojo.js script element to allow for declaration of Dojo’s configuration properties. Here we can specify settings like parseOnLoad, and isDebug. For example, we can load dojo.js with configuration information:

<script src="dojo.js" data-dojo-config="parseOnLoad: true, isDebug: true"></script>

data-dojo-* for widgets

The new data-dojo-type attribute replaces the dojoType attribute to specify the widget class to instantiate a target element. We can add the data-dojo-type to an HTML tag and the Dojo parser will create a widget on that element. This works in conjunction with the new data-dojo-props which replaces the attribute-to-property mapping previously used by the Dojo parser. We can also use the new data-dojo-id to create a new globally rooted variable to reference the new widget. For example, to declare a widget:

	 
	<div data-dojo-type="dijit.Dialog" data-dojo-props='title:"My Dialog",	 
		onFocus:function(){ /* a focus event handler */ }'	 
		data-dojo-id="myDialog">	 
	</div>	 

This will create a new dijit.Dialog widget, with the title property and onFocus handler set. It will make the widget available from the myDialog global variable. Remember to have parseOnLoad set to true or explicitly execute dojo.parser() (from dojo/parser) after the page is loaded to ensure the widget gets instantiated.

Within widget templates, we can also use the new data-dojo-attach-event and data-dojo-attach-point as replacement for dojoAttachEvent and dojoAttachPoint to register attach points and attach event handlers. And finally, we can also use a data-dojo-event to define the event to register for <script type="dojo/method"> scripts.

When to go Declarative

Even when leveraging the new HTML5-valid custom attributes, there are still pros and cons to declaring widgets within HTML instead of with JavaScript. Declaring JavaScript components from within HTML introduces semantic impurity since the HTML is no longer purely semantic markup, but includes tight coupling to particular visual components. The declarative approach also incurs extra CPU cycles because dojo.parse() must traverse the DOM tree to find elements with Dojo custom attributes. Programmatic instantiation avoids unnecessary cycles and preserves semantic purity of HTML. However, markup-based widget declaration still has a powerful advantage by allowing us to define and create a widget in a single place, facilitating rapid application development and progressive enhancement with minimal effort.

Dojo still provides backward compatibility with the old custom attributes, but the new data-dojo-* attributes leverage the new HTML5 specification to provide fast and efficient declaration of widgets and configuration with clean and validating syntax.

Comments

  • David

    Are there any documented differences for widgets that use the declarative approach versus ones that keep everything in the JavaScript? I assume that you would still need to run the query selector on these code fragments to hook up all the pieces of your widget which doesn’t happen instantaneously.

  • Hey there David,

    If the widget is in the Dijit namespace, there should be no differences to document, really. The same code is executed and they’re created in effectively the same ways. Widgets that support children can prove a bit more cumbersome to create programmatically, but the process winds up running the same code in most every case with no real distinctions between the two approaches.

    When you create a widget programmatically, as you point out, there is still the cost to query through the generated document pieces to look for things like data-dojo-attach-point properties and such, but the cost is quite minimal, since it’s searching through an in-memory-only DOM structure, and not something actually in the document of the page yet. When going declaratively with parseOnLoad: true, you pay a much heavier cost in terms of CPU time, as the parser has to query the entire document for a specialized and potentially very slow selector, and not just a very small memory-only fragment.

    Creating large structures programmatically can be somewhat cumbersome in code, but it does show gains in performance. Going declaratively to rapidly build up interfaces is incredibly handy, and once you have something working that way, you can move to programmatic instantiation if you want to try to squeeze more performance out.

    The only major difference that most people slip up on (myself included) is that when you create something in the dijit/layout namespace and you do so programmatically, once it’s all structured up, you *need* to call the startup method on the created structure. Create your BorderContainer, add ContentPanes or whatever as appropriate, and then call startup on the BorderContainer or you get nothing. It’s a very easy mistake to forget to startup. You don’t have to call it on all the child widgets (the main parent will do that for you) but you *do* have to kick it off at the top level.

  • Gerard

    Very informative. The documentation in general lacks procedural examples. A policy of procedural example before declarative example would help solve this or at least improve it.

    Declarative styles are very useful for prototyping, there’s no doubt about it, but, and there is a but, moving to the procedural style is painful, primarily because of how procedurally-anemic the docs are.

  • Dooo

    Dojo removes custom data attributes from HTML tags! This is awful.

  • No, it does not. It has a parser that converts some markup into other markup, but only for the specific data attributes of data-dojo-*.

  • Dooo

    I have no success in using Knockout.js library with Dojo UI. Knockout uses HTML data attributes to bind view model & HTML & after Dojo parses HTML all that data attributes are gone, so no two binding.

  • Ok, then don’t run the parser on those nodes… set parseOnLoad to false in your dojoConfig, and then call parser.parse() only on the nodes that need to be parsed, or better yet, instantiate all widgets dynamically rather than using the parser.

  • Dooo

    But I need to parse them because they are Dojo widgets & they must have two way data binding provided by Knockout. By “instantiate all widgets dynamically” you mean create them programmatically using JavaScript?

  • I know others have successfully used Knockout with Dojo 1.x, so I’m not sure exactly why this isn’t working. I did mean programmatic rather than dynamic. That said, if the parser is really just losing anything with data-*, that’s surprising and sounds like a bug. I’d be happy to review/consider a pull request to fix it if you have time to look at the code in dojo/parser and make sure that attributes with data-* are retained on the widget node (after confirming that they are being removed of course).

  • Dooo

    I was wrong but still it is not simple & too complicated for me. There is abandoned program “Knockout-Dojo connector” https://github.com/imankulov/knockout-dojo-connector which is working solution for some cases.