Skip to main content

Zen Mojo Tutorials

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:

  1. Getting started with the tutorial

  2. How this sample works

  3. Exercises

Tutorial 1: Getting Started

To start this tutorial:

  1. Open Studio and switch to the SAMPLES namespace.

  2. Open the class ZMbasics.Tutorial1.HomePageOpens in a new tab.

  3. Click View > Web Page. Or press F5.

    You then see the following page:

    generated description: tutorial1 pageintro

  4. Click the Developer Details button generated description: icon devdetails. The page then looks like this:

    generated description: tutorial1 devdetails

    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 generated description: icon devdetails 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.HomePageOpens in a new tab 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:

  • The id attribute is mainView. This attribute determines the unique identifier of the component.

  • The developerMode attribute is true, which means that the documentView displays the Developer Details button generated description: icon devdetails .

  • The ongetlayout attribute specifies how to lay out the physical appearance of this documentView. This attribute is responsible for the values in the Layout section of the Developer Details view.

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.TemplateOpens in a new tab, 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:

  • Modify the pageContents XData block so that it does not include the HTML helper plugin. Recompile the page class and redisplay the page. What do you see? Then undo your change and recompile.

  • In the myGetMainViewLayout() method, customize the $header or $p objects. For example, set the style attribute of each. This attribute specifies an inline CSS style to apply to that layout object.

  • Disable developer mode for the documentView and see the page as a user would see it. Hint: To do this, modify the pageContents XData block.

  • In the pageContents XData block, change the id of the documentView from mainView to mainViewNEW and recompile. How does this change affect the page? Assuming that you cannot change this id back to its original value, what additional changes are necessary to make the page work again?

Tutorial 2: Data Objects

This tutorial looks at a slightly more complex Zen Mojo page. This tutorial has the following parts:

  1. Getting started with the tutorial

  2. How this sample works

  3. Exercises

Tutorial 2: Getting Started

To start this tutorial:

  1. In Studio, in the SAMPLES namespace, open the class ZMbasics.Tutorial2.HomePageOpens in a new tab.

  2. Click View > Web Page. Or press F5.

    You then see the following page (but with different data):

    generated description: tutorial2 pageintro

  3. Click the Developer Details button generated description: icon devdetails at the bottom of the page. The central area of the page then displays the following Developer Details view:

    generated description: tutorial2 devdetails

    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.HomePageOpens in a new tab 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.TemplateOpens in a new tab, 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:

generated description: tutorial2 devdetails data

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:

  • Modify the template so that it returns additional data. For example, add the following lines to %OnGetJSONContent(), at a suitable location:

     set pObject.HomeCity = tPerson.Home.City
     set pObject.FavoriteColors = tPerson.FavoriteColors
    

    Then recompile the template class, view the Zen Mojo page, and display the Developer Details.

  • Modify the myGetMainViewLayout() method of the template class to display the new data. For example, add a comma after '=[personDOB]' } and then add the following lines:

                { type: '$p',  $content:'=[HomeCity]' },
                { type: '$p',  $content:'=[FavoriteColors]' }
    
    

    Then recompile the template class and view the Zen Mojo page.

  • In the myGetMainViewLayout() method, customize the $header or $p objects.

  • Change the value of the PROVIDERLIST parameter from mainViewData to mainViewNEWProvider and then recompile. How does this change affect the page? Assuming that you cannot change the PROVIDERLIST parameter back to its original value, what additional changes are necessary to make the page work again?

Tutorial 3: Event Handling

This tutorial focuses on event handling in Zen Mojo. This tutorial has the following parts:

  1. Getting started with the tutorial

  2. How this sample works

  3. Exercises

Tutorial 3: Getting Started

To start this tutorial:

  1. In Studio, in the SAMPLES namespace, open the class ZMbasics.Tutorial3.HomePageOpens in a new tab.

  2. Click View > Web Page. Or press F5.

    You then see the following page (but with different data):

    generated description: tutorial3 pageintro

  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:

  • The layout graph includes button elements.

  • The template class defines the method onselect().

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

  • Display the JavaScript console for the browser that you are using. The details depend upon the browser, but this console is generally found with other developer tools. Click buttons on the Zen Mojo page and notice the corresponding log entries in this console.

  • Add another button to the display. For this button, display both the two $div objects.

  • Add another button, specifically to display the third person from Sample.PersonOpens in a new tab.

FeedbackOpens in a new tab