Dojo 1.8 and AMD

An overview with demos

Karsten Lehmann, Mindoo GmbH / @klehmann79

About us

  • IBM Business Partner and a Notes/Domino Design Partner
  • Eclipse/Expeditor plug-ins and rich client applications
  • XPages applications
  • Web application development for IBM Websphere and Oracle Glassfish
  • Karsten Lehmann and Tammo Riedinger
  • Since 2004, developer of MindPlan for Haus Weilgut GmbH, mindmapping and project management for IBM Notes


  • Understanding concepts behind Dojo 1.8
  • Reference book for new APIs
  • Ideas and notes for individual experiments
  • Tips for using Dojo in XPages in IBM Notes/Domino R9

What is Dojo?

  • Comprehensive, freely usable web toolkit
  • APIs usable for Web and Mobile
  • One toolkit: no clear separation in Web and Mobile
  • Dojo 1.8 is part of IBM Notes/Domino R9!

What is Dojo?

An SDK with four sections:

  • dojo – general tools for JS development and Ajax
  • dijit – UI components, e.g. layout and form elements
  • dojox – additional UI components, including Mobile UI
  • util – tools for build generation and unit tests

Where do I find help?

  • Dojo API documentation (link)
    comprehensive collection of tutorials, reference and API documentation
  • Sitepen blog (link)
  • Final solution:
    Dojo source code – everything is open source!

Dojo releases

  • July 2010 - Dojo 1.5
  • March 2011 - Dojo 1.6
  • October 2011 - Lotus Notes 8.5.3 with Dojo 1.6
  • December 2011 - Dojo 1.7
  • August 2012 - Dojo 1.8
  • March 2013 - IBM Notes 9.0 with Dojo 1.8
  • May 2013 - Dojo 1.9
  • ? - Dojo 2.0 (roadmap discussion)

Differentiation between jQuery, Dojo, extJS

ExtJS / Sencha Touch

  • Strong separation between data and presentation
  • Mixed license: open source and commercial
  • Many commercial components available
  • Support by manufacturer Sencha


  • Largest developer community
  • Visually highly appealing jQuery plug-ins
  • Syntax requires getting used to
  • Little abstraction from browser DOM


  • Comprehensive toolkit for Web and Mobile
  • Few extensions / additional components on the net
  • Can be visually enhanced with jQuery
  • First class citizen in XPages, part of the framework

New in Dojo 1.8 - Web

dojox/calendar (demo)

(has scalability issues)

New in Dojo 1.8 - Web

dojox/dgauges (demo)

New in Dojo 1.8 - Web

dojox/treemap (demo)

New in Dojo 1.8 - Mobile

28 new widgets:
selection dialogs, progress bars, audio/video, scrolling areas inside pages, badge icons (demo)

New in Dojo 1.8

  • First components without support for Firefox 3.6 and IE6
  • XPages in the Notes Client R9 still based on the Firefox 3.6 engine!

New since Dojo 1.6 (Notes 8.5.3)

  • Even more widgets
  • Web: among others dgrid – flexible table component
  • Mobile: 21 new widgets
    e.g. Pop-up dialogs (opener, tooltip), ComboBox, SpinWheel
  • Additional information: link

New since Dojo 1.6 (Notes 8.5.3)

  • AMD: Asynchronous Module Definition
  • Loads Dojo classes and individual code, replaces dojo.require()
  • Many APIs renamed and reorganized for 2.0,
    old APIs still usable though
  • Considerably smaller Dojo core, loading additional modules on demand


  • Free WYSIWYG editor for Dojo applications
  • Web and Mobile
  • Available for download or to be used in the cloud (link)

Create web layouts –
declarative approach

Create web layouts –
declarative approach

  • Layout in the form of HTML tags
  • Width and shape adjustable via CSS style
  • Variety of layout containers that can
    be nested available
  • Used mainly for static contents


  • Well suited as basic layout
  • Five areas: top, left, right, bottom and center
  • Only center has to be filled
  • Several widgets per area through layoutPriority attribute (defines sequence)


design="headline", two widgets for "right" here


The same layout with design="sidebar":


<!DOCTYPE html>
<script type="text/javascript"
<link rel="stylesheet" type="text/css"
<link rel="stylesheet" type="text/css"
html,body {
<script type="text/javascript">
  <!-- load required widgets -->
    require( ['dijit/layout/BorderContainer',
      function(BorderContainer, ContentPane) {
<body class="claro">
<!-- BorderContainer -->
<div id="mainContainer" data-dojo-type="dijit/layout/BorderContainer"

  <!-- contained ContentPanes -->
  <div id="topPane" data-dojo-type="dijit/layout/ContentPane"
    data-dojo-props="region:'top'" style="height:30px">
      Top pane

  <div id="leftPane" data-dojo-type="dijit/layout/ContentPane"
    data-dojo-props="region:'left',splitter:true" style="width:20%">
      Left pane

  <div id="centerPane" data-dojo-type="dijit/layout/ContentPane"
      center pane

  <div id="rightPane1" data-dojo-type="dijit/layout/ContentPane"
    data-dojo-props="region:'right',layoutPriority:1" style="width: 10%">
      1st right pane from right

  <div id="rightPane2" data-dojo-type="dijit/layout/ContentPane"
    data-dojo-props="region:'right',layoutPriority:2" style="width: 10%">
      2nd right pane from right

  <div id="bottomPane" data-dojo-type="dijit/layout/ContentPane"
      first bottom pane


data-dojo-* attributes

  • HTML5 conform attribute names
  • data-dojo-config
    central Dojo configuration
<script type="text/javascript"

Global variable alternative:

<script type="text/javascript">
  parseOnLoad: true
<script type="text/javascript" src="/path/to/dojo.js"></script>

data-dojo-* attributes

  • data-dojo-type
    Class name of widget (separator " / " or " . ")
  • data-dojo-props (optional)
    Widget properties (cf. API documentation)
<div id="topPane" data-dojo-type="dijit/layout/ContentPane"
  data-dojo-props="region:'top'" style="height:30px">
    Top pane


  • AMD command for loading classes
  • Blocking or asynchronous depending on the mode
  • Calls up callback as soon as classes are available
  • Necessary for tags to become widgets
<script type="text/javascript">
  <!-- load required widgets -->
    require( ['dijit/layout/BorderContainer',
        function(BorderContainer, ContentPane) {
          //Callback with access to load classes

Dojo Parser

  • Parser can also be called manually
  • parseOnLoad: false
  • Advantage:
    Callback call as soon as widgets are generated
<script type="text/javascript">
  require( ['dijit/layout/BorderContainer', 'dijit/layout/ContentPane',
    'dojo/parser', 'dojo/ready'],
    function(BorderContainer, ContentPane, parser, ready) {
      //dojo/ready waits for DOM to load
      ready(function() {
        parser.parse().then(function(arrWidgets) {
          //called with array of all created widgets
            for (var i=0; i<arrWidgets.length; i++) {
              console.log('Widget created: '+arrWidgets[i].id);

Other layout widgets

  • dijit/layout/ContentPane
    Container for random DOM nodes
  • dijit/layout/AccordionPane
    Several areas below each other, one visible
  • dijit/layout/TabContainer
  • dojox/layout/ExpandoPane
    Closable sidebar
  • dojox/layout/GridContainer
    Portal layout

Portal layout

Portal with two portlets

<!DOCTYPE html>
<script type="text/javascript"
<link rel="stylesheet" type="text/css"
<link rel="stylesheet" type="text/css"
<link rel="stylesheet" type="text/css"
<link rel="stylesheet" type="text/css"
html,body {width:100%;height:100%;margin:0;overflow:hidden}
.gridContainerTable {border:0;height:inherit}
.gridContainer > div {height:inherit}
<script type="text/javascript">
    require( ['dijit/layout/BorderContainer',
    'dijit/layout/ContentPane', 'dojox/layout/GridContainer',
    'dojo/parser', 'dojo/ready',
    function(BorderContainer, ContentPane, GridContainer, parser,
    ready, Portlet) {
        ready(function() {
<body class="soria">
<div id="mainContainer" data-dojo-type="dijit/layout/BorderContainer"
  data-dojo-props="design:'sidebar'" style="width: 100%; height: 100%">

<!-- Portal visible in center area -->
<div id="portal" data-dojo-type="dojox/layout/GridContainer"
  style="height:100%" data-dojo-props="nbZones:3,region:'center',
  <!-- First portlet -->
  <div id="portlet1" data-dojo-type="dojox/widget/Portlet"
  data-dojo-props="title:'Portlet 1',column:1">
    Hello World.

  <!-- Second portlet -->
  <div id="portlet2" data-dojo-type="dojox/widget/Portlet"
  data-dojo-props="title:'Portlet 2',closable:false,column:2">
    Greetings from Entwicklercamp.

Portal layout

3 columns, portlets movable via drag and drop

Demo: portal layout

Generating widgets in JavaScript

  • Widget generation in JavaScript
  • Very flexible in interaction with Ajax
  • Dojo widgets form a tree structure:
require(['dijit/registry', 'dijit/layout/ContentPane'],
  function(registry, ContentPane) {

  //add widgets via addChild()
  //main: existing dijit/layout/BorderContainer
  var mainContainer=registry.byId('main');
  var newPanel=new ContentPane({
    id: 'contentpane1',
    content: 'Pretty dynamic content '+(new Date()).toString(),
    splitter: true
  //resize recalculates positions

  //read contained widgets via getChildren()
  var arrChildren=mainContainer.getChildren();

  //remove widgets via removeChild()
  var childWidget=arrChildren[0];
  //if no longer needed, free up all resources

Demo: dynamic UI

Form widgets

Form widgets

Widgets can be placed freely, either declarative:

Lorem ipsum dolor sit amet.<br />
<input type="text" data-dojo-type="dijit/form/TextBox" /><br />
consetetur sadipscing elitr.

Form widgets

...or programmatic:

require(['dojo/_base/window', 'dojo/dom', 'dijit/registry'],
  function(win, dom, registry) {
    //get target DOM node with ID 'targetDomNodeId':
    var targetDomNode=dom.byId('targetDomNodeId');
    //get existing widget with ID 'myWidgetId':
    var myWidget=registry.byId('myWidgetId');
    //Change widget position
    //(first/last=first/last child,
    //before/after=before/after reference node)
    myWidget.placeAt(targetDomNode, 'first');

Demo: form widgets overview


A collection of important APIs:

(Please learn all of them by heart! ;-) )

Important widget APIs

Widget can be located via its ID

// dijit/registry
var widget=registry.byId('widgetId1');

Reading/writing of properties

var propValue=myWidget.get('value')
myWidget.set('value', 'xyz');

Important DOM APIs

DOM node can be located via its ID

// dojo/dom
var nodeWithId=dom.byId('nodeId1')

Reading and changing styles

// dojo/dom-style
var styleValue=domStyle.get(node, 'display');
domStyle.set(node, 'backgroundColor', '#ff0000');

Important DOM APIs

Reading/writing DOM node classes

// dojo/dom-class
var nodeHasClass=domClass.has(node, 'myclass');
domClass.add(node, 'myclass');
domClass.remove(node, 'myclass');

Generating and placing DOM nodes

// dojo/dom-construct
var createdNode=domConstruct.create('div',
  {innerHTML:'<b>Test</b>'}, refNode, 'first');, otherNode, 'before');

Dimensions of DOM node

// dojo/dom-geometry
var box=domGeom.getMarginBox(node);
//box.width, box.height,, box.left

Important DOM APIs

Finding DOM nodes via CSS Selector

// dojo/query
var arrNodes = query('.headline', bodyNode);

Wichtige Dojo-APIs

Language-dependant date formatting

// dojo/date/locale
var formattedDateStr=locale.format(myDate, {selector:'date'});

Conversion between date and ISO8601 format

// dojo/date/stamp
var parsedDate=stamp.fromISOString(isoDateStr);
var dateAsString=stamp.toISOString(mydate);

Searching a value in arrays

// dojo/_base/array
var index=array.indexOf(myArray, valueToFind);

Important Dojo APIs

Parsing JSON strings and formatting objects as JSON

// dojo/json
var parsedJsonObj=JSON.parse("{'foo':'bar'}");
var jsonStr=JSON.stringify( {foo:'bar'} );

…and finally:

// dojo/_base/lang
// clone object recursively
var clonedObj=lang.clone(obj);

// run code in different scope
var myfunction=lang.hitch(mygrid,
  function(key, value) {this.set(key, value);} );
myfunction('store', newStore);

// check for data type:
lang.isArray(x) / lang.isFunction(x) / lang.isObject(x) /

// replacing text
lang.replace("Hello {name.first} {name.last}!",
  { name: {first:  "Rudi", last: "Knegt"} });

Registering events

Reacting to events

The new dojo/connect

dojo.connect was divided:

  • dojo/on - DOM events
  • dojo/aspect - hooks for class methods


"on" in the event name is cut out:

//Register event code for onClick event:
//uses dojo/dom and dojo/on
var myDomNode=dom.byId('nodeId');
var signal=on(myDomNode, 'click',
  function(evt) {alert('Node clicked'); });
//unregister event code:

Event delegation

Intercepting 'bubbling’ events in parent containers

<div id="parentDiv">
  <button id="button1" class="clickMe">Click me</button>
  <button id="button2" class="clickMe">Click me also</button>
  <button id="button3" class="clickMe">Click me too</button>
  <button id="button4" class="clickMe">Please click me</button>
require(["dojo/on", "dojo/dom", "dojo/domReady!"],
  function(on, dom, domReady) {
    var myObject = {
      id: "myObject",
      onClick: function(evt){
        alert("The scope of this handler is " +;
    var div = dom.byId("parentDiv");
    on(div, ".clickMe:click", myObject.onClick);


  • Aspect-oriented programming
  • aspect.before, aspect.after and aspect.around
require(['dojo/aspect', 'dojo/json', 'dojo'],
  function(aspect, JSON, dojo) {
  //overwrite old method 'dojo.xhrGet()'
  aspect.around(dojo, "xhrGet", function(originalXhr) {
    return function(args) {
      var t0=new Date().getTime();
      //call original method
      var deferred = originalXhr(args);

      //we add a callback to the deferred object
      deferred.then(function(data) {
        var t1=new Date().getTime();
        console.log("Data read in "+(t1-t0)+
          "ms with request: "+JSON.stringify(args));

      //and forward it to the caller
      return deferred;


  • Publish/subscribe architecture
  • Decouples message sender from recipient
  • used for drag and drop system:
    /dnd/start, /dnd/cancel, /dnd/drop
require(['dojo/topic'], function(topic) {
  topic.subscribe("some/topic", function(event){
    // process object 'event'
  //publish new event object to all subscribers
  topic.publish("some/topic", {name:"My Birthday Party",

Working with data

Web forms and Ajax

Dojo forms

  • dijit/form/Form simplifies working with web forms
  • Reading and writing form data as a JS object
  • Validating the form with myform.validate()

Dojo forms

dijit/form/Form becomes FORM tag in DOM:

<div id="myformid" data-dojo-type="dijit/form/Form">
      <td><input type="text" name="firstname"
        data-dojo-type="dijit/form/TextBox" /></td>
      <td><input type="text" name="lastname"
        data-dojo-type="dijit/form/TextBox" /></td>

Dojo forms

Form data can be extracted and set:

require(['dojo/json', 'dijit/registry'],
  function(JSON, registry) {
    var myform=registry.byId('myformid');
    var formData=myform.get('value');
    //show form data as JSON string:

    //update form fields based on
    //"name" attribute of fields
    myform.set('value', {firstname:'Rudi', lastname:'Knegt'});

    //validate form
    if (!myform.validate())
      alert('Form content invalid!');

Demo: reading/writing form data

Ajax requests


  • Replaces dojo.xhrGet() / .xhrPost()
  • xhr package also comprises cross domain protocols like IFrame/JSONP
require(["dojo/request/xhr"], function(xhr) {
  xhr("myxagent.xsp", {
    handleAs: "json"
    method: "GET"
  }).then(function(data) {
        //process data (here JS object of JSON data)
      }, function(err) {
        //report/log error
      }, function(evt){
        //process progress info
        //(requires browser support for XHR2)

Demo: Notes views with LazyTreeGrid


Asynchronous Module Definition


  • Class loader for Dojo classes and individual code
  • Experimental in Dojo 1.6, standard since 1.7
  • New asynchronous mode generates script tags instead of xhr
  • Better performance in browser than with xhr
  • New API distribution leads to smaller code units
  • More compact custom builds, but also more HTTP requests without optimization

More HTTP requests?

Surely, it can’t be that many!

That was our grid example :-)


  • Custom builds (tutorial)
  • XPages runtime optimizer:
    "Use runtime optimized JavaScript and CSS resources"
  • Combines Dojo classes and dependencies

Asynchronous class loading

Activation with data-dojo-config

<script type="text/javascript" src="path/to/dojo.js"
  • async:false (Default)
    Loading of Legacy APIs, e.g. dojo.connect, dojo.xhrGet etc.
  • async:true
    Loading only dojo nano kernel (small)
  • With XPages in R9, unfortunately always async:false

Legacy APIs

With async:true, legacy APIs can be loaded as "dojo" module:

require(['dojo'], function(dojo) {


Defining individual AMD modules


Syntax analogous to require:

  • Integrating dependencies
  • Callback function called after loading process
  • The difference: We give something in return!
//Content of "/subdir/db.nsf/dojo/mindoo/tools/XspUtil.js":
define(['dojo/query'], function(query) {
  //return simple JS object with one method
  return {
    //getClientId finds DOM nodes with ID ending with sComponentId
    getClientId: function(sComponentId) {
      var arrNodes=query("[id$='"+sComponentId+"']");
      if (arrNodes && arrNodes.length>0) {
        var sId=arrNodes[0].id;
        return sId;


Using the defined module:

  • Define the package location
  • Load modules/classes
<script type="text/javascript">
    { name:'mindoo', location:'/subdir/db.nsf/dojo/mindoo' }
<script type="text/javascript" src="path/to/dojo.js"></script>
<script type="text/javascript">
  //use classname of new module in require call:
  require(['mindoo/tools/XspUtil', 'dojo/domReady!'],
    function(XspUtil, domReady) {
      //call new defined method:
      var clientId=XspUtil.getClientId('mytextfield');
      alert(clientId); // view:_id1:mytextfield

define for advanced users

Inheritance of classes with define:

define(['dojo/_base/declare', 'dojox/data/QueryReadStore'],
  function(declare, QueryReadStore) {
    //create class "mindoo/data/QueryReadStoreExt" as subclass
    //of "dojox/data/QueryReadStore"
    //optional 1st parameter with classname in declare() call,
    //becomes global variable:
    return declare("mindoo/data/QueryReadStoreExt", [QueryReadStore], {

       fetch:function(request) {
         request.serverQuery = {};
         //call superclass method:
         return this.inherited("fetch", arguments);

The result can be loaded via require and instantiated with new.

Loading files

  • AMD special module "module" delivers path to current class
  • AMD plugin "dojo/text" loads files via Ajax
require(['module', 'dojo/dom'],
  function(module, dom) {
    var moduleUri=module.uri;
     //compute template path
     var templatePath=moduleUri+"/../templates/mytemplate.html";
     //load HTML file
     require(['dojo/text!' + templatePath], function(template) {
        dom.byId('content').innerHTML = template;

Parsing of template and value replacement e.g. with
Django template language dojox/dtl

Now there is potential!

Demo: Activity stream in NSF

Integration in XPages

Using widgets

Activating Dojo option "parseOnLoad" with the Dojo panel of the XPage:

Using widgets

Entering required Dojo classes in the resource tab:

Notation with " . " in R9 Beta is required here to be able to use JS Optimizer

Using widgets

  • Equipping tags with Dojo type and attributes
  • For layout widgets either with xp:div or xp:panel

Using widgets

Analog approach for fields:

Using individual classes

Defining package location with
"Resources / Add / Dojo Module Path Resource",
then adding class as "Dojo module"

Using individual classes

Location of Dojo file in DB Design (package explorer)

Partial-refresh-resistant surfaces

  • Partial refresh sends field contents to the server that recalculates the page area
  • Returned HTML is injected into the page and parsed for Dojo widgets mark-up
  • May lead to a reset of widget properties:
    active tabs, scroll position in BorderContainer etc.
  • Solution: using partial refresh selectively or not at all

Finally readable Dojo sources!

  • New feature in Notes/Domino R9:
    "Use uncompressed resource files (CSS & Dojo)"
  • Worth a mint for the debugging of problems

Thank you!

Time for questions!


Dojo is great because:

Dojo features


Dojo features

Dojo Mobile 1.7 and 1.8


Dojo 2.0


Dojo forms


Event handling

Drag and Drop




Special effects

Mobile Scrollpane


Alternative UI components

Custom Builds