Using Zen Mojo
Zen Mojo Tutorials
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   
Search:    

This chapter contains tutorials to help you to become familiar with the basics of Zen Mojo. It discusses the following topics:

The tutorials use the sample classes in the ZMbasics package, which are provided in the Zen Mojoversion numberDemos.ZIP file. For setup information, see the Readme.txt file in that ZIP file.
Tutorial 1: Layout Graphs
This tutorial explores a simple Zen Mojo page, focusing on layout graphs. This tutorial has the following parts:
Tutorial 1: Getting Started
To start this tutorial:
  1. Open Studio and switch to the SAMPLES namespace.
  2. Open the class ZMbasics.Tutorial1.HomePage.
  3. Click View > Web Page. Or press F5.
    You then see the following page:
  4. Click the Developer Details button . The page then looks like this:
    The Data section displays data that is currently available to this part of the page. In this example, no data is available. We will examine this section again in the next tutorial.
    The Layout section displays the information used to lay out the visual contents of this part of the page. This information is also contained in a JSON object called a layout graph. This object has a property named children, which is an array of objects.
    Important:
    The Developer Details option does not display these objects in their literal form. It does not display valid JavaScript syntax.
  5. Click the Developer Details button again to display the page normally.
How This Sample Works
This section discusses how the sample works. It discusses the following topics:
Page Definition
First, let us see how the page is defined. ZMbasics.Tutorial1.HomePage contains the following XData block:
XData pageContents [ XMLNamespace = "http://www.intersystems.com/zen" ]
{
<pane xmlns="http://www.intersystems.com/zen" 
xmlns:mojo="http://www.intersystems.com/zen/mojo" layout="none">
<mojo:documentView id="mainView" 
developerMode="true"
ongetlayout="return zenPage.getContent('mainViewLayout',key,criteria);">
<mojo:mojoDefaultPageManager>
<mojo:HTML5Helper/>
</mojo:mojoDefaultPageManager>
</mojo:documentView>

</pane>
}
This definition controls the pageContents pane, which is (in most cases) the only area of the page that you customize. In this case, the pageContents pane is a large rectangle in the middle of the page; for most plugins, however, the pageContents pane is automatically resized to fill the entire page.
Each item within the pageContents pane is a component and is displayed as a rectangular area within this pane. This pageContents pane contains one component, which is an instance of <mojo:documentView> (or simply documentView).
This documentView is defined as follows:
Component is a Zen term. A Zen Mojo page can include other components (such as content providers), but typically you work directly only with the documentView component (or multiple documentView components). This book thus generally uses the more specific term documentView.
Depending on the plugins you use, a page can contain multiple documentViews; in other cases, only one documentView is supported. In general, if a page manager plugin is intended for use on mobile devices, that plugin uses the entire page and does not support multiple documentViews.
Introduction to getContent()
The ongetlayout attribute is defined as follows:
ongetlayout ="return zenPage.getContent('mainViewLayout',key,criteria);"
The getContent() method is a Zen Mojo system method that returns a content object (a data object or a layout graph). In this example, the only argument that is used is the first one (providerName). Each documentView can have its own content objects. In this case, the page has only one documentView, which has one possible content object (mainViewLayout), as you will see later.
The getContent() method does the following:
  1. It invokes the onGetContent() method of the associated template class. If that method returns content, the system returns that content.
    To find the initial template class, Zen Mojo examines the TEMPLATECLASS parameter of the page class.
  2. If onGetContent() returns null, the system checks to see whether the page cache contains any content. If so, the system returns that content.
  3. If there is no cached content, the system invokes the %OnGetJSONContent() method of the associated template class, uses the result to create the content, and then returns that content.
The onGetContent() and %OnGetJSONContent() methods are application-specific methods of the template class. The getContent() method is a system method of the page class.
How the documentView Component Is Laid Out
As noted in the previous section, getContent() invokes the onGetContent() method of the associated template class. In this case, the template class is ZMbasics.Tutorial1.Template, and the onGetContent() method of that class is as follows:
ClientMethod onGetContent(providerName, key, criteria) [ Language = javascript ]
{
    var content = null;

    // dispatch to convenient methods
    // if content is null, then the %OnGetJSONContent method will be called

    switch(providerName) {
    case 'mainViewLayout':
        content = this.myGetMainViewLayout(key,criteria);
        break;
    }
    return content;
}
As you can tell by its name, myGetMainViewLayout() is an application-specific method. It is defined as follows:
ClientMethod myGetMainViewLayout(key, criteria) [ Language = javascript ]
{
    var myLayoutGraph = {};
    //The standard technique is to have a switch/case construct that creates 
    //branches based on the key argument;
    //In this case only one key value is possible, so there is no need to branch

    myLayoutGraph = {
        children: [
            { type: '$header', $content: 'Zen Mojo Tutorial 1'},
            { type: '$p',      $content: 'This page displays some simple text.'},
            { type: '$p',      $content: 'Here is another paragraph.' },
        ]
        

    }
    return myLayoutGraph;
}
This method returns a Zen Mojo layout graph, which is a JSON object. A layout graph has a property named children, which contains an array of layout objects: one $header and two $p objects. These layout objects are defined in the helper plugin.
Note that Zen Mojo generally lays out the items in the order in which the layout lists them, so in this case, the header is displayed at the top, followed by the paragraphs. For finer control over placement, InterSystems recommends using CSS.
A browser uses the Zen Mojo layout graph (together with other instructions provided by Zen Mojo), generates HTML 5.0, and displays the page.
How the Sample Defines the Geometry
When you use the default page manager, the page class should define the method adjustContentSize(). The purpose of this method is to specify the size and position of each documentView in the pageContents pane.
This method receives, as input, the width and height of pageContents pane. These dimensions vary depending on the current screen size and rotation. The method also receives the input argument load, which is 1 when the page is loaded and is 0 at other times.
In this case, the adjustContentSize() method is as follows:
ClientMethod adjustContentSize(load, width, height) [ Language = javascript ]
{
    // This method should have an if{} block for each component. 
    
    var mainView = zen('mainView');
    if (mainView) {
        mainView.setSize(width, height);
        var mainDiv = mainView.getEnclosingDiv();
        mainDiv.style.top =  '0px';
        mainDiv.style.left = '0px';
    }
}
The syntax zen('mainView') is a reference to the documentView whose id is mainView. To specify the geometry of that component, the method invokes instance methods of and sets properties of that component.
Exercises
A good way to learn a technology is to make your own modifications to a functioning sample. Try the following exercises:
Tutorial 2: Data Objects
This tutorial looks at a slightly more complex Zen Mojo page. This tutorial has the following parts:
Tutorial 2: Getting Started
To start this tutorial:
  1. In Studio, in the SAMPLES namespace, open the class ZMbasics.Tutorial2.HomePage.
  2. Click View > Web Page. Or press F5.
    You then see the following page (but with different data):
  3. Click the Developer Details button at the bottom of the page. The central area of the page then displays the following Developer Details view:
    The Data section displays data that is currently available to this part of the page. This data is contained in a JSON object called a data object. This object has properties called personDOB and personName.
    As we saw in the previous tutorial, the Layout section displays the information that is contained in the layout graph. Note that in this case, the layout graph refers to values that you see in the Data section.
How This Sample Works
This section discusses how the sample works. It discusses the following topics:
Page Definition
First, let us see how the page is defined. ZMbasics.Tutorial2.HomePage contains the following XData block:
XData pageContents [ XMLNamespace = "http://www.intersystems.com/zen" ]
{
<pane xmlns="http://www.intersystems.com/zen" 
xmlns:mojo="http://www.intersystems.com/zen/mojo" layout="none">
<mojo:documentView id="mainView" 
developerMode="true"
ongetdata="return zenPage.getContent('mainViewData',key,criteria);" 
ongetlayout="return zenPage.getContent('mainViewLayout',key,criteria);">
<mojo:mojoDefaultPageManager>
<mojo:HTML5Helper/>
</mojo:mojoDefaultPageManager>
</mojo:documentView>

</pane>
}
This definition contains one new element that was not present in the previous sample. The documentView specifies the ongetdata attribute, which specifies how to retrieve data from the server, to be available in this documentView. This attribute is responsible for the values in the Data section of the Developer Details view.
How the Sample Gets Data from the Server
The ongetdata attribute specifies how to retrieve the data for use by this documentView. This attribute is specified as follows:
ongetdata="return zenPage.getContent('mainViewData',key,criteria);" 
As noted in the previous tutorial, getContent() invokes the onGetContent() method of the associated template class, passing its arguments to that method. In this case, the template class is ZMbasics.Tutorial2.Template, and its getContent() method is as follows:
ClientMethod onGetContent(providerName, key, criteria) [ Language = javascript ]
{
    var content = null;

    // dispatch to convenient methods
    // if content is null, then the %OnGetJSONContent method will be called

    switch(providerName) {
    case 'mainViewLayout':
        content = this.myGetMainViewLayout(key,criteria);
        break;
    }
    return content;
}
As you can see, this method returns null if the providerName argument is mainViewData. Because the onGetContent() method of a template returns null in this case, Zen Mojo then automatically calls the %OnGetJSONContent() method of the same class. In this example, this method is as follows:
ClassMethod %OnGetJSONContent(pProviderName As %String, pKey As %String, ByRef pParms, 
   Output pObject As %RegisteredObject, pCriteria As %RegisteredObject, pLoad As %Boolean = 0) 
   As %Status
{

    // The standard technique is to have an outermost if/elseif construct
    // based on the pProviderName argument; in this case there is only one
    // possible value for pProviderName. 
    if (pProviderName = "mainViewData") {
        
        // Within a pProviderName branch, the standard technique is to have an
        // if/elseif construct based on the key argument.
        // In this case, there are no keys, so there is no need to branch 

        set pObject = ##class(%ZEN.proxyObject).%New()

        set tPerson = ##class(Sample.Person).%OpenId(1)
        set pObject.personName=tPerson.Name
        set pObject.personDOB=$zdate(tPerson.DOB,3)
    
    } ; additional pProviderName branches would go here
    
   quit $$$OK
}

}
This method creates an instance of %ZEN.ProxyObject and sets properties of that object, to carry data to return to the client. (The class %ZEN.ProxyObject does not have any predefined properties but instead is a special-purpose container object that can have any property. For an introduction, see Zen Proxy Objects in Developing Zen Applications.)
This method returns the %ZEN.ProxyObject as an output object. Zen Mojo converts that object to a JSON object and passes the JSON object to the client. The client receives the data that you see in the Developer Details view:
How the Sample Gets Data from the Server: JSON Providers
One more element is needed to make data available from the server: the PROVIDERLIST parameter. This parameter must list the names of all data objects to be created on the server; this must include the main branches in %OnGetJSONContent().
In this example, the page class defines this parameter as follows:
Parameter PROVIDERLIST = "mainViewData";
Another Look at Layout Graphs
For this template, the following method defines the layout graph used on this page:
ClientMethod myGetMainViewLayout(key, criteria) [ Language = javascript ]
{
    var myLayoutGraph = {};

    //The standard technique is to have a switch/case construct based on the key argument;
    //In this case only one key value is possible, so there is  to branch

    myLayoutGraph = {
        children: [
            { type: '$header', $content:'Zen Mojo Tutorial 2'},
            { type: '$p',      $content:'Below are details for the first person in Sample.Person.'},
            { type: '$p',      title:'Name', $content:'=[personName]' },
            { type: '$p',      title:'Birth Date', $content:'=[personDOB]' }
        ]
        

    }
    return myLayoutGraph;
}
Note that the last two $p objects display data obtained from the data object. The syntax =[name] retrieves the value of a given property of the data object.
Exercises
A good way to learn a technology is to make your own modifications to a functioning sample. Try the following exercises:
Tutorial 3: Event Handling
This tutorial focuses on event handling in Zen Mojo. This tutorial has the following parts:
Tutorial 3: Getting Started
To start this tutorial:
  1. In Studio, in the SAMPLES namespace, open the class ZMbasics.Tutorial3.HomePage.
  2. Click View > Web Page. Or press F5.
    You then see the following page (but with different data):
  3. Press the Show Person 2 button and notice how the display changes.
How This Sample Works
This section discusses how the sample works. This sample is different from the one in the previous tutorial in two ways:
First, let us examine the layout graph, which is provided by the following method in the template class:
ClientMethod myGetMainViewLayout(key, criteria) [ Language = javascript ]
{
    var myLayoutGraph = {};

    //The standard technique is to have a switch/case construct based on the key argument.
    //In this case, the layout is not key-specific layout, so there is no need to branch.

    myLayoutGraph = {
        children: [
            { type: '$header', $content: 'Zen Mojo Tutorial 3'},
            { type: '$p'},
            { type: '$button', $content:'Show Person 1', key:'showPerson1'},
            { type: '$p'},
            { type: '$button', $content:'Show Person 2', key:'showPerson2'},
            { type: '$p'},

            { type: '$div', key:'person1',
               children:[
                { type: '$p', title:'Name', $content:'=[person1Name]' },
                { type: '$p', title:'Birth Date', $content:'=[person1DOB]' }
                ]},

            { type: '$div', key:'person2', hidden:true,
               children:[
                { type: '$p', title:'Name', $content:'=[person2Name]' },
                { type: '$p', title:'Birth Date', $content:'=[person2DOB]' }
                ]},

        ]
        

    }
    return myLayoutGraph;
}
Notice that this layout graph includes two $button layout objects and specifies a key value for each one. After the buttons, the layout graph has two $div objects, one of which is initially visible and one of which is hidden.
Now let us examine the onselect() method. Zen Mojo automatically calls this method when the user selects an item on the page. This method is defined as follows:
ClientMethod onselect(key, value, docViewId) [ Language = javascript ]
{
   console.log('in '+docViewId+ ' select: ' + key + ' value: ' + value);
   if (docViewId=='mainView') {
      var person1=zen('mainView').getItemByKey('person1');
      var person2=zen('mainView').getItemByKey('person2');

       if (key=='showPerson1') {
          person1.$show();
          person2.$hide();
      } else if (key=='showPerson2') {
          person1.$hide();
          person2.$show();
      }
   
   }
}
The method receives, as an argument, the id of the documentView where the select event occurred; this enables us to customize the behavior in each documentView. In this case, there is only one documentView. The other arguments are the key and value of the selected item.
The console.log line writes a line to the JavaScript console. In this case, the line just provides information about the values passed to the onselect() method.
The method uses the syntax zen() to access the documentView component and then uses the method getItemByKey() to access specific items in the layout graph.
Depending on the selected key, the method then controls which parts of the layout graph are visible. Note that the HTML5 helper plugin provides the $show() and $hide() methods. Other helper plugins provide other tools. For details on each plugin, see Using Zen Mojo Plugins.
Exercises