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