Search code examples
javascriptajaxdojojs-amd

How to use dijit requires in parsed dojo ContentPane


I am trying to do a simple task. This task is to load a HTML containg dijit.Form into a ContentPane. I don't know which dijits I will need before I load this HTML, but the loaded HTML will contain applicable require's to load them.

So in order to be able to execute the script from loaded HTML I use dojox.layout.ContentPane. However when I set parseOnLoad to true, the parsing takes place before the script execution, so the dijits aren't available when first loading the content. Also when I try to use onDownloadEnd callback, when this callback is run, the dijits from require's are still not loaded.

Only thing I can think of myself is using setTimeout to defer parsing to a time when these scripts will be executed. I don't like this solution however as it may fail from time to time and it would make the application less responsible.

So how should I perform the parsing so that it happens right after the require statement from loaded HTML is run?


Solution

  • I can see two possible solutions - both with dijit/layout/ContentPane:

    1. Use Dojo 1.8.0, as the parser supports auto require, it will load dependencies itself as you can see here: http://jsfiddle.net/phusick/vr4h4/

    2. Put the list of dependencies somewhere into your form template, e.g. in data-config attribute of your dijit/form/Form:

      <form 
          data-dojo-type="dijit.form.Form" 
          data-config='"deps":["dijit/form/Form", "dijit/form/TextBox", "dijit/form/Button"]'>
      
          <input data-dojo-type="dijit.form.TextBox" data-dojo-props="placeholder:'TextBox'">
          <button data-dojo-type="dijit.form.Button">Button</button>
      
      </form>
      

      Set parseOnLoad:false for the dijit/layout/ContentPane, load the template, get the list of dependencies, require them and then in the factory function parser.parse() containerNode of your ContentPane (see it in action http://jsfiddle.net/phusick/QA4gH/):

      require([
          "dojo/ready",
          "dojo/dom",
          "dojo/query",
          "dojo/on",
          "dojo/parser",
          "dojo/json",
          "dijit/layout/ContentPane",
          "dojo/domReady!"
      ], function(ready, dom, query, on, parser, JSON) {
      
          var template, dijits;
      
          ready(function() {
              template = dom.byId("template").textContent;
              on.once(dom.byId("loadFormButton"), "click", loadForm);
              contentPane1.set("parseOnLoad", false);
              contentPane1.on("load", parseForm);
          });
      
          function loadForm() {
              contentPane1.set("content", template);  
          }
      
          function parseForm() {
              // a node to parse
              var node = contentPane1.containerNode;
              // obtain a list of dependencies
              var config = JSON.parse("{" + query("form", node)[0].dataset.config + "}");
      
              // require (AMD load) dependencies
              require(config.deps, function() {
                  // parse ContentPane content when dependencies are resolved
                  dijits = parser.parse(node); 
                  console.log(dijits); // an array of instantiated dijits
              });
          }      
      });
      ​
      

    EDIT: I just got this idea that writing an auto require (for Dojo <1.8) is just about adding a short getDependencies() method, so you don't need to list dependencies as I mentioned in the second option above:

    function getDependencies(/*DOMNode*/ containerNode) {
        var deps = [];
        query("[data-dojo-type]", containerNode).forEach(function(node) {
            var dep = node.dataset.dojoType.split(".").join("/");
            if(!~array.indexOf(deps, dep)) {
                deps.push(dep);
            };            
        });
        return deps;
    }
    

    See it working at jsFiddle: http://jsfiddle.net/phusick/hnjWt/