Dojorama Part 1: Getting Started

This article is part of the series Dojorama: Building a Dojo Single Page Application

Let's start by setting up a virtual host and add some empty files directly in the root directory:

<webroot>
    + package.js
    + package.json

Don't worry about those package.* files just yet - all it means is that this is also the package root where our application code will live.

Putting It Under Git

  • cd <webroot>
  • git init
  • git add -A
  • git commit -m 'Initial import'

Getting Dojo

Now we want to add our first vendor libraries which obviously will be dojo and mijit. We'll add more dependencies later.

  • git submodule add git://github.com/dojo/dojo.git vendor/dojo/dojo
  • git submodule add git://github.com/sirprize/mijit.git vendor/sirprize/mijit

This leaves us with the following structure:

<webroot>
    + package.js
    + package.json
    + vendor
        + dojo
            + dojo
        + sirprize
            + mijit

A First Widget

We'll start by creating a navigation widget to be placed on all our pages. The HTML template resides in its own file and while we're at it, we'll add native language support by creating an external file containing localized content. Don't worry about all the details yet, just create those files and copy/paste the code:

The Navigation Widget

ui/_global/widget/NavigationWidget.js

define([
    "dojo/_base/declare",
    "mijit/_WidgetBase",
    "mijit/_TemplatedMixin",
    "dojo/text!./templates/NavigationWidget.html",
    "dojo/i18n!./nls/NavigationWidget"
], function (
    declare,
    _WidgetBase,
    _TemplatedMixin,
    template,
    nls
) {
    return declare([_WidgetBase, _TemplatedMixin], {
        templateString: template,

        postCreate: function () {
            this.inherited(arguments);
            this.homeNode.innerHTML = nls.homeLabel;
            this.releasesNode.innerHTML = nls.releasesLabel;
        }
    });
});

The Navigation Template

ui/_global/widget/templates/NavigationWidget.html

<ul>
    <li><a href="#" data-dojo-attach-point="homeNode"></a></li>
    <li><a href="#" data-dojo-attach-point="releasesNode"></a></li>
</ul>

The Localized Navigation Content

ui/_global/widget/nls/NavigationWidget.js

define({
    root: {
        homeLabel: 'Home',
        releasesLabel: 'Releases'
    }
});

Our First Page

We're ready to build a top-level page widget representing the application's homepage:

The Homepage Widget

ui/home/HomePage.js

define([
    "dojo/_base/declare",
    "mijit/_WidgetBase",
    "mijit/_TemplatedMixin",
    "dojo/query",
    "../_global/widget/NavigationWidget",
    "dojo/text!./templates/HomePage.html",
    "dojo/text!./css/HomePage.css"
], function (
    declare,
    _WidgetBase,
    _TemplatedMixin,
    query,
    NavigationWidget,
    template,
    css
) {
    return declare([_WidgetBase, _TemplatedMixin], {
        templateString: template,

        postCreate: function () {
            this.inherited(arguments);
            var navigationWidget = new NavigationWidget({}, this.navigationNode);

            // setting style
            var styleElement = window.document.createElement('style');
            styleElement.setAttribute("type", "text/css");
            query('head')[0].appendChild(styleElement);

            if (styleElement.styleSheet) {
                styleElement.styleSheet.cssText = css; // IE
            } else {
                styleElement.innerHTML = css; // the others
            }
        }
    });
});

There's quite a lot going on already: This widget is our page-level controller and it is using an external template HomePage.html and stylesheet HomePage.css. When everything is loaded, the widget initializes the navigation widget and creates a <style> tag in the <head> section of the containing page and places its style definitions into it. All this work is done in the postCreate() method which is fired after all properties of a widget are defined, and the document fragment representing the widget is created.

The Homepage Template

ui/home/templates/HomePage.html

<div>
    <div data-dojo-attach-point="navigationNode"></div>
    <h1>Home</h1>
</div>

The Homepage CSS

ui/home/css/HomePage.css

body {
    background: yellow;
}

The HTML

tests/app/source/index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Dojorama</title>
        <script>
            document.write('<style media="all">#static { display: none; }</style>');
        </script>
    </head>
    <body>
        <div id="static">
            Some static or server-side generated content for search engines and clients with disabled JavaScript
        </div>

        <div id="page"></div>

        <script>
            var dojoConfig = {
                async: 1,
                cacheBust: 1,
                packages: [ // paths are relative to vendor/dojo/dojo/dojo.js
                    { name: 'dojorama', location: '../../..' },
                    { name: 'mijit', location: '../../sirprize/mijit' }
                ]
            };
        </script>

        <script src="/vendor/dojo/dojo/dojo.js"></script>

        <script>
            require(['dojorama/ui/home/HomePage', 'dojo/domReady!'], function(HomePage) {
                var page = new HomePage({}, 'page');
                page.startup();
            });
        </script>
    </body>
</html>

That's it. The page widget will be placed into the #page element of our HTML page. Point your browser to http://localhost/tests/app/source/index.html and check out this beauty. Also note the document.write(...) portion in the <head> section: if JavaScript is available and enabled, this will immediately insert a style rule to hide the #static element and all it's contents.

But what is really going on here? Glad you asked: those define(...) statements tell the Dojo loader to load the modules we need in our code. All the modules in this tutorial follow the Asynchronous Module Definition (AMD) format. The widget's lifecycle is managed by mijit/_WidgetBase, HTML templating is handled by mijit/_TemplatedMixin and internationalization is handled by dojo/i18n.

Our Current Layout

<webroot>
    + package.js
    + package.json
    + ui
        _global
            + widget
                + NavigationWidget.js
                + nls
                    + NavigationWidget.js
                + templates
                    + NavigationWidget.html
        + home
            + HomePage.js
            + css
                + HomePage.css
            + templates
                + HomePage.html
    + tests
        + app
            + source
                + index.html
    + vendor
        + dojo
            + dojo
        + sirprize
            + mijit

Conclusion

We now have a sweet little UI component hierarchy containing one global widget and one page. The page is able to load its own template and dynamically load and apply the CSS to style this template. Looks like we're ready to turn it all into a single page application