Programmatic page layouts using dojo and existing markup

The layout tutorials for dojo that I’ve seen all seem to fall into two categories:

  • Markup-based: adding dojoType properties to HTML elements in the markup
  • Programmatic: creating HTML elements in JavaScript

When using a toolkit such as dojo for layout rather than standard CSS, my preference would be to keep the dojo layout stuff entirely in JavaScript, separate from the markup, whilst still using HTML to describe my content. This allows an easy transition to/from dojo and CSS layout techniques, doesn’t clutter the markup with dojo specific stuff that would only be needed when JavaScript is enabled, and just provides a cleaner separation. I was sure this must be possible in dojo and it is; it just doesn’t seem to be well documented anywhere.

After playing for a while (and with quite a bit of help from James), I turned this…

<script type="text/javascript">
dojo.require("dijit.layout.BorderContainer");
dojo.require("dijit.layout.TabContainer");
dojo.require("dijit.layout.AccordionContainer");
dojo.require("dijit.layout.ContentPane");
</script>

<div dojoType="dijit.layout.BorderContainer"
  style="width: 100%; height: 100%;">
  <div dojoType="dijit.layout.ContentPane" region="top">
    Top pane
  </div>
  <div dojoType="dijit.layout.AccordionContainer" region="leading">
    <div dojoType="dijit.layout.AccordionPane" title="pane #1">
      accordion pane #1
    </div>
    <div dojoType="dijit.layout.AccordionPane" title="pane #2">
      accordion pane #2
    </div>
    <div dojoType="dijit.layout.AccordionPane" title="pane #3">
      accordion pane #3
    </div>
  </div>
  <div dojoType="dijit.layout.TabContainer" region="center">
    <div dojoType="dijit.layout.ContentPane" title="tab #1">
      tab pane #1
    </div>
    <div dojoType="dijit.layout.ContentPane" title="tab #2">
      tab pane #2
    </div>
    <div dojoType="dijit.layout.ContentPane" title="tab #3">
      tab pane #3
    </div>
  </div>
  <div dojoType="dijit.layout.ContentPane" region="trailing">
    Trailing pane
  </div>
  <div dojoType="dijit.layout.ContentPane" region="bottom">
    Bottom pane
  </div>
</div>

<style type="text/css">
 html, body {
 width: 100%;
 height: 100%;
 margin: 0;
 }
</style>

…into this…

<script type="text/javascript">
  dojo.require("dijit.layout.BorderContainer");
  dojo.require("dijit.layout.TabContainer");
  dojo.require("dijit.layout.AccordionContainer");
  dojo.require("dijit.layout.ContentPane");

  dojo.ready(function () {
    var mainContainer = new dijit.layout.BorderContainer(
      {}, 'mainContainer');
    var topPane = new dijit.layout.ContentPane(
      {'region': 'top'}, 'topPane');
    mainContainer.addChild(topPane);
    var leftPane = new dijit.layout.AccordionContainer(
      {'region': 'leading'}, 'leftPane');
    var accordionPane1 = new dijit.layout.AccordionPane(
      {'title': 'pane #1'}, 'accordionPane1');
    var accordionPane2 = new dijit.layout.AccordionPane(
      {'title': 'pane #2'}, 'accordionPane2');
    var accordionPane3 = new dijit.layout.AccordionPane(
      {'title': 'pane #3'}, 'accordionPane3');
    leftPane.addChild(accordionPane1);
    leftPane.addChild(accordionPane2);
    leftPane.addChild(accordionPane3);
    mainContainer.addChild(leftPane);
    var centerPane = new dijit.layout.TabContainer(
      {'region': 'center'}, 'centerPane');
    var tabPane1 = new dijit.layout.AccordionPane(
      {'title': 'tab #1'}, 'tabPane1');
    var tabPane2 = new dijit.layout.AccordionPane(
      {'title': 'tab #2'}, 'tabPane2');
    var tabPane3 = new dijit.layout.AccordionPane(
      {'title': 'tab #3'}, 'tabPane3');
    centerPane.addChild(tabPane1);
    centerPane.addChild(tabPane2);
    centerPane.addChild(tabPane3);
    mainContainer.addChild(centerPane);
    var rightPane = new dijit.layout.ContentPane(
      {'region': 'trailing'}, 'rightPane');
    mainContainer.addChild(rightPane);
    var bottomPane = new dijit.layout.ContentPane(
      {'region': 'bottom'}, 'bottomPane');
    mainContainer.addChild(bottomPane);
    mainContainer.startup();
  });
</script>

<div id="mainContainer">
  <div id="topPane">Top pane</div>
  <div id="leftPane">
    <div id="accordionPane1">accordion pane #1</div>
    <div id="accordionPane2">accordion pane #2</div>
    <div id="accordionPane3">accordion pane #3</div>
  </div>
  <div id="centerPane">
    <div id="tabPane1">tab pane #1</div>
    <div id="tabPane2">tab pane #2</div>
    <div id="tabPane3">tab pane #3</div>
  </div>
  <div id="rightPane">Trailing pane</div>
  <div id="bottomPane">Bottom pane</div>
</div>

<style type="text/css">
  html, body, #mainContainer {
    width: 100%;
    height: 100%;
    margin: 0;
  }
</style>

There’s lots of code but I prefer the separation. In reality I’d move the JavaScript etc into a separate files but it’s easier to demonstrate like this.

A couple of gotchas:

  • Adding extra HTML elements dynamically
    Sometimes dojo will require extra divs for layout purposes (for different digit classes, e.g. dijit.layout.BorderContainer). Clearly it would be wrong to modify markup to include extra divs just for this so you’ll probably want to create them programmatically. This is fine, but instead of using addChild to append a child, you’ll need to place the new element in the DOM yourself using dojo.place(myDynamicElement.domNode, myExistingElement.domNode);.
  • Specifying the top level widget
    If you use dojo’s markup method (with djConfig="parseOnLoad:true" set or running dojo.parser.parse()), the top level widgets are determined automatically. With this method, we need to manually start it by calling startup() on the top level widget (in our case, the mainContainer element). Otherwise, no layout occurs at all.
Advertisements

7 thoughts on “Programmatic page layouts using dojo and existing markup

  1. Hi, for the past 2 days I have been trying to disable a particular tab contained in the TabContainer which is simply a ContentPane. However I am unable to. dijit.byId(‘tabid’).disabled = true; does not work. Can anybody suggest what can be done?

      • Thanks Gareth for confirming. Yes I tried the workarounds but they didn’t work too … let me explore further …do reply if you get to know something … 🙂

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