SOS

Shane O'Sullivan's technical blog… really ties the room together

Writing a Django Template Widget With Dojo Data Stores

Posted by Shane O'Sullivan on March 3, 2008

One of the very cool recent additions to the Dojo toolkit is support for the Django Template engine. It is essentially a very advanced browser based templating engine, that enables you to use things like FOR loops, IF statements and much more directly in a HTML template. Or, as the author puts it:

The Django Template Language is one part of Django, a “high-level Python Web framework that encourages rapid development and clean, pragmatic design.

This blog post is an in depth tutorial on working with DTL, Atom XML and Dojo data stores. To see the final working version, have a look here, or get the code from here. Extract the code at the same level as Dojo, and open the demoAtomDTL.html file. Note that you need either the nightly Dojo code, or v1.1 or later for this to work.

Simple Example

As a very simple example, you could write a single template, such as

<ul>
    <!--{% for item in items %}-->
        <li value="{{item.value}}">{{item.text}}</li>
    <!--{% endfor %}-->
</ul>

Then, you populate the template with some JSON data, e.g.

{
    items:[
        {value:1,text:"Choice 1"},
        {value:2,text:"Choice 2"},
        {value:3,text:"Choice 3"}
    ]
}

and it generates the following HTML.

<ul>
    <li value="1">Choice 1</li>
    <li value="2">Choice 2</li>
    <li value="3">Choice 13</li>
</ul>

Writing A Widget And Template To Work With Atom XML

The example above is simplistic, though still very useful of course. However it is possible to do much more interesting things with DTL. A recent enhancement to the code base means that a template can now be built using data from a dojo.data repository, rather than a simple JSON object. This means that you can have a single template that can be used with data from many different data sources (see here for an ItemFileReadStore and here for a Flickr data store example).

This post shows how to write a templated widget that uses a Dojo data store I have written for reading Atom XML data (which has been committed to the Dojox project), and transforming it using DTL into a nice fancy HTML widget, complete with visual effects. See http://www.skynet.ie/~sos/blog.php to see the final result. Do a “View Source” on that page to see how simple it is to include it on a page.

A Django templated widget built from an Atom XML file

Writing the Template

Firstly, the structure of the HTML to be produced must be decided. For this example, I’ll just create a series of DIV elements that contain a header for the title, and a body for the text. The body will also contain another DIV to list all the tags (or categories in Atom-speak). So, a single entry will end up looking like:

<div class="entry">
    <div class="entryTitle">This is an entry title</div>
    <div class="entrySummary">
        This is some summary text
        <div>
            Tags: <a href="http://shaneosullivan.wordpress.com/category/ajax">Ajax</a>
        </div>
    </div>
</div>

A template for this looks as follows:

<!--{% load dojox.dtl.contrib.html %}-->
<div id="{{rootId}}" >
    <!--{% for item in items %}-->
        <div class="entry">
            <div class="title"><!--{{item.title.text}}--></div>
            <div class="summary">
                <!--{% if item.summary.type == "html" %}-->
                    <!--{% html item.summary.text %}-->
                <!--{% else %}-->
                    <!--{{ item.summary.text }}-->
                <!--{% endif %}-->
            <div>
                <!--{% if item.category %}-->
                    Tags:
                    <!--{% for cat in item.categorys %}-->
                        <a href="{{cat.scheme}}/category/{{cat.term}}"> <!--{{cat.term}}-->  </a>
                    <!--{% endfor %}-->
                <!--{% endif %}-->
            </div>
        </div>
    </div>
<!--{% endfor %}-->

Break it down!

Ok, so let’s have a look at this.


<!--{% load dojox.dtl.contrib.html %}-->

This tells the template system to load an optional module that can convert text into HTML DOM nodes. This function is used when the summary type is “html”, meaning that the text contained in the data is acually HTML tags. The module is used on the line
<!--{% html item.summary.text %}-->
Here you can see a Django function , “html” being called – this takes the text in the item.summary.text data object and renders it to HTML, rather than creating a text node.


<div id="{{rootId}}" >

Give the root node of our template an ID. The rootId parameter must be provided by the widget. Note that when you want to put a piece of data in a HTML attribute, you do not need to escape it with <!–{{, just {{.


<!--{% for item in items %}-->

This is a FOR loop that iterates over all the elements of a data structure called items. This parameter must be provided by the widgets, and should be an array. The item (singular) is a value that can be referenced inside the loop, and is not something that must be provided by the widget. Note that {% is used for calling functions, for loops etc, and {{ is used to access data


<div class="title"><!--{{item.title.text}}--></div>

This creates a DIV, and places the value of item.title.text in it. The item parameter is the element of the items array that is currently accessed as part of the FOR loop. This item should have a parameter called title, which in turn should have a parameter called text. If it were a simple JSON object, it would look something like:

{ title: {text:"This is the title"}}

However, due to the wonder of the Dojo.data and dojox.DTL integration, it will also work if item is a data store item, that contains an attribute called title. In that case, the data will be retrieved using something like:

store.getValue(item, "title")

However, the template does not need to be concerned with this. Which is cool :-)


<!--{% if item.summary.type == "html" %}-->
    <!--{% html item.summary.text %}-->
<!--{% else %}-->
    <!--{{ item.summary.text }}-->
<!--{% endif %}-->

Here you see an IF statement being used. It checks to see if the summary has a type parameter equal to “html”. If so, it prints out the value as HTML, using the HTML function discussed above. Otherwise, it simply prints out the text verbatim.


<!--{% if item.category %}-->

This checks if the item has a parameter called category. Note that is not checking it for any particular value, just for existence.
<!--{% for cat in item.categorys %}-->
As before, this is a FOR loop. It iterates over an array. However, note the plural categorys. The actual name of the attribute is category, but because a plural is used, when item is a accessed using a data store, the getValues function is called instead of getValue. This ensures that an array is available.

<a href="{{cat.scheme}}/category/{{cat.term}}">
<!--{{cat.term}}--> </a>

This one is quite simple, just accessing the category. A category in Atom has a scheme and a term. The scheme can be thought of as a namespace, and the term is generally what you are interested in. Here you can see how to include multiple pieces of data in a single attribute. As this template was written to display a transformed Atom document, which comes from my blog, it is constructing a url that looks like http://shaneosullivan.wordpress.com/category/dojo.

And that’s it for the template!

Writing the Widget

The widget, called demo.AtomDtl, uses two mixin classes:

  • dijit._Widget – The standard base widget type.
  • dojox.dtl._HtmlTemplated – The base for a DTL widget that contains a template.

So, declare the widget like:

dojo.declare("demo.AtomDtl", [dijit._Widget, dojox.dtl._HtmlTemplated],
{
    templateString: '{% load dojox.dtl.contrib.data %}{% bind_data items to store as items %}{% include templateFile %}',
    templateFile: dojo.moduleUrl("dojox.data.demos.widgets.templates", "atomTemplate.html"),

The templateFile parameter points to the file name of the template described earlier. The templateString parameter enables the widget to use dojo.data stores. First it loads the dojox.dtl.contrib.data module, which adds special handling for data stores to DTL. Secondly, it states that the items parameter should be accessed using the store parameter.

So far so simple! Now we just have to retrieve the data, and tell the widget to render.

postCreate: function(){
    //Create the data store
    this.store = new dojox.data.AtomReadStore({url: this.href,unescapeHTML: true});
    var _this = this;
    //Set the rootId
    this.rootId = this.id+"_entries";
    //Tell the store to get all Atom entries
    this.store.fetch({
        query: {},
        onComplete: function(entries){
            _this.items = entries;
            _this.render();
        }
    });
}

This postCreate function

  1. Creates a new data store, dojox.data.AtomReadStore, which can interpret ATOM XML documents. This is not yet part of Dojo, but I am attempting to get it committed, see the ticket tracking it here.
  2. Sets a root ID to be used for the root element of the template.
  3. Calls the store’s fetch method. This retrieves the data, and passes an array of entries to the onComplete function.
  4. Adds the entries to the widget as the items parameter. This is what the template expects.
  5. Calls the render method.

That’s it for a simple widget! See the AtomDTL.js file in the demo zip file for the full version of this.

Extract that zip file alongside the latest version of Dojo. Open the file demoAtomDtl.html to see this widget in action. The widget code is in the AtomDtl.js file.

A more complex widget is available in AtomDtlAnim.js, which adds animations to the basic class. To see that in action, open the demoAtomDtl_animations.html file. Both widgets use the same template, and the same data source.

Enjoy!

Share this post:digg it|kick it|Email it|bookmark it|reddit|liveIt

About these ads

10 Responses to “Writing a Django Template Widget With Dojo Data Stores”

  1. Navid said

    Hi Shane,
    at first: thx for this basic but highly extendable tutorial about writing a widget using DTL, it was a good starting point.

    But as I tried your two demo files, there was an error, fortunately the same error twice ;)


    Could not load 'dojox.dtl._HtmlTemplated'; last tried '../dojox/dtl/_HtmlTemplated.js'

    Seems that _HtmlTemplated could not be loaded ? As I looked into the DTL Package, I couldn’t find neither dojo.declare(‘dojox.dtl_HtmlTemplated’) nor the simple string ‘_HtmlTemplated’

    Since you’re more into DTL I’m sure you could find that error faster than I.

    Sincerely Navid

    PS: Same error appears in firebug on this site

  2. Hi Navid,

    Do you have the latest Dojo code? This only works with the nightly build of dojo, not with v1.0. Apologies for not mentioning this in the post, I’ll update it

    Shane

  3. Navid said

    oh … so i just looked for some externals for my symfony plugins directory… but the trunk doesn’t look really organized to me…

    so is dojo 1.1 right ?? i hoped to find some externals… but the trunk is really some kind of weired.. .;)….

    just ACK me the 1.1 and i’ll start ;)

    greetings
    Navid

  4. Hi Navid,

    Yes, this is running against the latest code, which will be the version 1.1 when it is released in a week or two.

    I’m not sure what you mean about the trunk not being organized – there are 3 projects, Dojo, Dijit (the widgets), and DojoX (the experimental, aka cool, stuff). Just check out all three project using Subversion (TortoiseSVN is a great program if you’re on Windows), and you can get working on it. See http://www.dojotoolkit.org/community/svn for instructions on checking out the code.

    Thanks

    Shane

  5. […] AOL hosted Dojo with your custom codeDojo Grid has landedDojo theme browser shows off Dijit widgetsWriting a Django Template Widget With Dojo Data StoresUpgrading Ubuntu Feisty Fawn (7.04) to Gutsy Gibbon […]

  6. […] engine, that enables you to use things like FOR loops, IF statements and much more directly ihttp://shaneosullivan.wordpress.com/2008/03/03/writing-a-django-template-widget-with-dojo-data-store…Toshiba Support – Content DetailsPackage: WinZIP self-installing ZIP file. Can also be unZIPped […]

  7. trumncono said

    emm.. bookmarked )

  8. ben hockey said

    do you know if anyone has tried to incorporate something like this with the Grid? virtual scrolling and templated widgets would be a nice idea.

    – the other whose name escapes you ;)

  9. Hmm no idea. Bring it up tomorrow night maybe?

    Oh, and sorry about the name thing :-)

  10. Thanks for the article. I am new at django and this will be a big help.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 533 other followers

%d bloggers like this: