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

This chapter describes how to create layout methods, which are methods in the template class that describe the layout of your page. This chapter discusses the following topics:

Overview of Layout Methods and Layout Graphs
As noted earlier in this book, a layout method is a method, in a template class, that returns a layout graph. The onGetContent() method of the template class is responsible for invoking the layout methods in the same class. The onGetContent() method can pass two arguments to any layout method:
Formally, a layout graph is a JSON or JavaScript object that meets the following requirements:
The following simple example returns a static layout graph (which does not refer to the data object, to any variables, or to the special sourceData object). This example uses layout objects defined in the HTML5 helper plugin (see Helper Plugin for HTML5 in the book Using Zen Mojo Plugins):
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: $$$Text('Tutorial 1 - Sample Zen Mojo Page')},
            { type: '$p',      $content: $$$Text('This page displays some simple text.')},
            { type: '$p',      $content: $$$Text('Here is another paragraph.') },
        ]
        

    }
    return myLayoutGraph;
}
This method returns an object (called myLayoutGraph within this method), which has a property named children. The children property is an array that contains three objects. The first object is of type $header, and the second and third objects are of type $p. Note the use of the $$$Text() macro.
Referring to the Current Data Object
A layout graph can (and typically does) refer to properties in the data object. To refer to the value of a property (propertyname) of the data object, use '=[propertyname]'
To refer to a property of a property, you can use dot syntax. For example: '=[propertyname.subprop1]'
Similarly, if a property is an array, you can use square brackets and the array item number. For example: '=[arrayprop[3]]' or '=[arrayprop[3].subprop]'
Within a layout graph, when Zen Mojo finds a layout object property with a value of the form '=[propertyname]', it tries to find the given property (propertyname) in the current data object. If it finds the property, Zen Mojo inserts its value into the corresponding part of the layout graph. If it does not find the property, Zen Mojo uses the null value instead. Zen Mojo does not throw an error.
Note:
This syntax applies specifically within a layout graph and is not available elsewhere.
Suppose that the data object for a given documentView has the following properties:
The following example layout method displays data for this object. This example also uses layout objects from the HTML5 helper plugin (see Helper Plugin for HTML5 in the book Using Zen Mojo Plugins).
ClientMethod myGetMainViewLayout(key, criteria) [ Language = javascript ]
{
    var myLayoutGraph = {};
    myLayoutGraph = {
        children: [
            { type: '$header', $content: $$$Text('Data Object Demo Template')},
            { type: '$p', title:'Name', $content:'=[name]' },
            { type: '$p', title:'Birth Date', $content:'=[dob]' },
            { type: '$p', title:'Home City', $content:'=[homeaddress.city]' },
            { type: '$p', title:'First Favorite Color', $content:'=[favoritecolors[1]]' },
            { type: '$p', title:'Number of Favorite Colors', $content:'=[favoritecolors.length]' },
        ]
    }
    return myLayoutGraph;
}
Note:
'=[$variable]' Syntax
A few layout objects support the syntax '=[$variable]', where $variable is a variable provided by the layout object. For example, the $loop layout object defines variable $loopNumber for each item in a loop. See The $loop Layout Object in the book Using Zen Mojo Plugins for details and extended examples.
Invoking Template Methods in a Layout Graph
You can invoke a method from within a layout object using the syntax:
myLayoutProperty: '=[$method.methodname]'
where methodname is a string that will be passed to a callback method defined in the template class. When the callback is invoked, it will perform the operation defined for methodname and return an appropriate value.
Use the following general procedure to implement the callback:
The following example describes a simple onresolvemethod callback and demonstrates how it is used.
Example: Using the resolve() callback with simple values and loops
This example implements a callback method named resolve(). The onresolvemethod attribute is defined as follows:
  onresolvemethod="return zenPage.getTemplate().resolve(context,which);"
The resolve() method is implemented in the template class:
  ClientMethod resolve(context, which) [ Language = javascript ] {
    switch (which) {
      case 'readValue': return 'myValue = \"' + context.$instance.myValue + '\"';
      case 'readLoop': return 'myLoop('+context.$loopNumber+') = \"' + context.$loopValue + '\"';
    }
  }
The resolve() method deals with two different types of context object:
The following template method contains a layout graph that uses both callback options. It consists of two main layout objects: $p invokes the callback once (with '=[$method.readValue]'), and $loop invokes it repeatedly (with '=[$method.readLoop]').
  ClientMethod myMainLayout(key, criteria) [ Language = javascript ] {
    var myLayoutGraph = {};
    myLayoutGraph = { children: [
      { type: '$p', myValue: 'a single value' , $content: '=[$method.readValue]'},
      { type: '$loop', value:['nergles','frabsters'], 
        children: [ { type: '$div', $content: '=[$method.readLoop]'} ]
      }
    ]}
    return myLayoutGraph;
  }
The layout objects are rendered as follows:
When myLayoutGraph is rendered, the following text is displayed:
    myValue = "a single value"

    myLoop(1) = "nergles"
    myLoop(2) = "frabsters"
Specifying Style Attributes in Layout Graphs
A layout graph has attributes that control its overall style. Within a layout graph, you can specify attributes for layout objects that control their appearance as well.
The following fragment shows an example:
        content = {
            documentStyle:'background:white;min-height:100%;',
            children:[
                {type:'$para',
                    style:'line-height:150%;',
                    blockStyle:'padding-left:20px;padding-bottom:20px;',
                    title:'inbox',
                    titleStyle:'font-size:36px;color:#606060;',
                    text:'Messages and answers you have received',
                },
      ...
Most attributes that control appearance fall into two categories:
Using the sourceData Property in a Layout Graph
Within a layout method, you can bypass the data object, and instead use the special sourceData object.
Specifically, the layout graph can include an object-valued property named sourceData, which is handled specially. In this case, Zen Mojo uses the sourceData object as the current data object, instead of the usual data object.
Important:
If the layout graph includes the sourceData property, Zen Mojo does not invoke the ongetdata callback and does not have access to the data object normally provided by that method.
If the layout graph includes the sourceData property, the syntax '=[propertyname]' refers to properties of the sourceData object.
The following example show an example:
ClientMethod myGetMainViewLayout(key, criteria) [ Language = javascript ]
{

    var myLayoutGraph = {};
    myLayoutGraph = {
        sourceData: {
            name : 'Higgins,Bert',
            dob: '15-July-1973',
            homeaddress: {
                street: '4595 Center Street',
                city: 'Hopkinton',
                postalcode: '89304'
                },
            favoritecolors : ['blue']
            },
        children: [
            { type: '$header', $content: $$$Text('sourceData Demo')},
            { type: '$p', title:'Name', $content:'=[name]' },
            { type: '$p', title:'Birth Date', $content:'=[dob]' },
            { type: '$p', title:'Home City', $content:'=[homeaddress.city]' },
            { type: '$p', title:'First Favorite Color', $content:'=[favoritecolors[1]]' },
            { type: '$p', title:'Number of Favorite Colors', $content:'=[favoritecolors.length]' },
        ]
    }
    return myLayoutGraph;
}
In this example, the sourceData object is defined inline (that is, within the layout graph). You could instead use a reference to an object defined earlier:
        sourceData: myObject
Using Stashed Values within sourceData
The sourceData object provides a convenient way to use values that you have previously stashed on the client, so that you can avoid calling the server unnecessarily. Specifically, you can do the following:
  1. In appropriate places in the client methods, stash values by saving them in properties of the page instance or the template instance. For example:
    zenPage._MyNewValues={name:mainView.getControlValue('enterName'),
                          city:mainView.getControlValue('enterCity')};
    For details, see Stashing Values in the chapter Background Information and Tasks.”
  2. When you create a sourceData object, include references to the stashed values.
  3. Within the layout graph, refer to the sourceData object (as previously described in Using the sourceData Property in a Layout Graph). That is, use the syntax '=[propertyname]' to refer to properties of the sourceData object.