How to write templates using the component state object

by Michela Frigerio
15,949 views Published on Feb 15, 2018
Applies to: 7.2 or higher
Table of contents

Introduction

Content is the most important part of a Web application, and it should be presented in an engaging and professional way to provide the best user experience. Designing, which is the way a specific piece of information must be rendered for the user, is a web designer's main task when creating a Web application's visual identity. WebRatio Platform helps the web designer accomplish this task by enabling him or her to create custom layout templates for each view component used in the Web Project. This article explains how you can create your own layout templates and identifies the main concepts needed to write them.

Prerequisites

Writing layout templates for view components requires you to have a custom Style Project in your workspace. You can learn how to create it by reading this article.

What you need to know

You must know a couple of concepts to write layout templates for view components in the WebRatio Platform: the Component State Object and the Component Layout Information. The Component State Object is the structure of the Java Bean component. It is different for each View Component type. You can read the "Component State Object" article for further information. The Component Layout Information is the XML fragment stored in the Web Project containing the layout information for the specific view component. Even though the XML structure is quite similar for all view components, it's a good practice to check the view component's specific XML for which you are writing the layout template.

You can see the Component Layout Information specific to a view component of your Web Project following these steps:

  1. Select a View Component from a site view of your Web Project.
  2. Move to the Layout View.
  3. Select the same View Component in the Grid.
  4. Move to the Properties View.
  5. Select the XML tab.
  6. Press the Show Layout XML button.

The Component Layout Information's basic structure follows:

<layout:Unit id="dau1g" …. unitTagName="DataUnit"> 
  <layout:Attribute attribute="userName" …. name="username" … ….></layout:Attribute>  
  <layout:Attribute attribute="password" …. name="password" … ….></layout:Attribute>
  <layout:Link …. name="Logout" to="lou2" type="normal" validate="true"/>  
</layout:Unit>
  • Line 1. A layout:Unit node, which is the container of all the view component information. This node delimits the XML fragment you are interested in. The main information contained in this node are the id and the unitTagName.
  • Lines 2-3. One layout:Attribute node for each Display Attribute selected on the view component. The main information for each layout attribute are name and type.
  • Line 4. One layout:Link node for each Navigation Flow outgoing from the view component. The main information for each link are name and type.

For form-based View Components, the Component Layout Information does not include <layout:Attribute> nodes but does include <layout:Field> nodes.

How to create a Layout Template

Anytime you want to write your own layout template, you need to:

  1. Go to the main menu.
  2. Select File > New > Layout Template.
  3. Select Component as the Template Type.
  4. Select the View Component type for which you want to create the layout template.

  5. Press the Next button to proceed.
  6. Choose the target Style Project.
  7. Write a name for the template.
  8. Press the Finish button to complete the procedure.

How to define a Details Layout Template

Let's suppose you want to create a basic layout template for a Details Component that shows to the user a two-column table. In the first column, the user sees the label of the information reported in the same row but in the second column. The table has as many rows as the number of the information shown by the Details Component. You can see an example of the desired graphic in the following image, which shows the company's detailed information using the desired graphic.

You need to know the structure of the Component State Object. See the "Details Component State Object" section of the "Component State Object" article for further information. This is the code you need to write in your template to get this result:

<table>
  <wr:Iterate var="attr" context="unit" select="layout:Attribute">
    <tr>
      <th valign="top" class=" header">
        <wr:Label/>
      </th>
      <td valign="top" class=" value">
        <wr:Value/>
      </td>
    </tr>
  </wr:Iterate>
</table>
  • Line 2. The <wr:Iterate> WebRatio Generation Tag retrieves the list of elements expressed by the select attribute from the XML fragment represented by the context attribute (in this case it is the "unit" one). Then, for each element, it executes its body. In this example for each <layout:Attribute>, a row of the table is printed in the JSP page. Each row has two columns.
  • Line 5. The <wr:Label> WebRatio Generation Tag renders an element's label. In this example, it retrieves the label of the <layout:Attribute> considered by the current iteration, which is the name of the element in the Web Project. The tag directly produces the text label. If the application is localized, then the <wr:Label> produces a <bean:message> Struts Tag which prints at runtime the translated label according to the current locale. Refer to "How to localize a Web application" for further information.

  • Line 8. The <wr:Value> WebRatio Generation Tag renders an element's value. In this example it renders the value of the <layout:Attribute> considered by the current iteration. An attribute's value of must be evaluated at runtime since it is contained in the Component State Object. This is the reason why the <wr:Value> produces a JSP code fragment printed in the JSP page. In particular, you get a <c:out> JSTL Tag that prints on the Web browser the attribute's value contained in the Component State Object.

How to print Navigation Flows

Along with the information about the object details, a Details Component may have outgoing Navigation Flows that are usually rendered in the page as anchors. This is the code you need to write to add a section in the template retrieving all modeled Navigation Flows and to print them. In this example, each link is printed in a dedicated table column.

def links = unit.selectNodes("layout:Link")
[% if(links != null && links.size() > 0){ %]
  <tr><td>
[% } %]
<wr:Iterate var="attr" context="unit" select="layout:Link">
  <wr:Link/>
</wr:Iterate>
[% if(links != null && links.size() > 0){ %]
  </td></tr>
[% } %]
  • Line 1. A Groovy scriptlet that retrieves how many <layout:Link> are modeled on the Details Component. The expression used by the selectNodes() method is an XPath expression.
  • Lines 2-4. A Groovy scriptlet deciding whether to add a new row depending on the <layout:Link> number.
  • Lines 5-7. A <wr:Iterate> WebRatio Generation Tag is used to iterate over links and print each of them.
  • Line 6. The <wr:Link> WebRatio Generation Tag renders the Navigation Flow of an element. In this example it renders the Navigation Flow considered by the current iteration. Usually this tag produces an HTML anchor having the Navigation Flow destination as target URL.

How to define a Simple List Layout Template

Let's suppose you want to create a basic layout template for a Simple List Component that shows a data grid containing a list of elements, one for each row. Each row shows the list of links on the right that represents the actions associated with each element. You can see an example of the desired graphic in the following image.

You need to know the structure of the Component State Object. See the "Simple List Component State Object" section of the "Component State Object" article for further information.  This is the code you need to write to get the previous result:

<table border="0" cellspacing="1" cellpadding="2">
  <tr>
    <wr:Iterate var="l" context="unit" select="layout:Attribute">
      <th>
        <wr:Label/>
      </th>
    </wr:Iterate>
    <wr:Iterate var="l" context="unit" select="layout:Link">
      <th></th>
    </wr:Iterate> 
  </tr>
  <c:forEach var="current" varStatus="status" items="${<wr:Id context="unit"/>.data}">
    <c:set var="index" value="${status.index}"/>
    <tr> 
      <wr:Iterate var="attr" context="unit" select="layout:Attribute">
        <td>
          <wr:Value/>
        </td>
      </wr:Iterate>
      <wr:Iterate var="l" context="unit" select="layout:Link">
        <td>
          <wr:Link class="link"/>
        </td>
      </wr:Iterate> 
    </tr>
  </c:forEach>
</table>
  • Lines 2-11. This section creates the table header. Two iterations handled with <wr:Iterate> WebRatio Generation Tag handles two iterations, one for the attributes and one for navigation flows, which obtain the exact number of table columns.
  • Line 12. The <c:forEach> JSTL Tag iterates over all the objects included in the data property of the Component State Object. It prints in the Web browser a row for each contained element of the list.
  • Line 13. The <c:set> JSTL Tag sets a variable's value. In this case, it sets the current iteration index's value. This is necessary to extract from the Component State Object the information related to the current element of the list to be printed out.
  • Lines 15-19. A <wr:Iterate> WebRatio Generation Tag is used to iterate over attributes and print a table column for each of them with the correspondent value.
  • Lines 20-24. A <wr:Iterate> WebRatio Generation Tag is used to iterate over flows and print a table column for each with the corresponding link.

How to define a List Layout Template

Let's suppose you want to create a basic layout template for a List Component that shows a data grid containing a list of elements, one for each row. Each row shows the list of links on the right that represents the actions associated with each element. Moreover at the bottom there are links for moving between different pages and links for jumping to a specific page. You can see an example of the desired graphic in the following image.

The Component Layout Information of the List Component showing the company information is the same as the Simple List. In addition there are links related to pagination and sorting.

How to print sorting links

The sorting links correspond to the attributes chosen in the Sort Attributes property of the List Component.

This is the code you need to write to add a section in the template retrieving all the attributes chosen for the sorting and to print them in the JSP page. The link is printed in the header of the column related to the sorting attribute, wrapping the attribute label.

[% def isSortable = unit["sortable"]
... %]  
<wr:Iterate var="att" context="unit" select="layout:Attribute">
  <th nowrap="nowrap" class="<wr:StyleClass/> header">
    [% if (isSortable == "true") { %]
      [% def sortLink = unit.selectSingleNode("layout:Link[@link='" + unit["id"] + att["attribute"] + "']")
        if(sortLink != null) { %]
          <wr:Link context="sortLink" class="sort" type="sort"/>
      [% } else { %]
        <wr:Label/>
      [% } %]
    [% } else { %]
      <wr:Label/>
    [% } %]
  </th>
</wr:Iterate>
  • Line 1. A Groovy variable retrieving whether the component is sortable or not.
  • Line 6. A Groovy scriptlet retrieving, using XPath, how many <layout:Link> are used to sort the list.
  • Lines 7-9. A Groovy scriptlet deciding whether to print the sorting link depending on the sortLink variable.

How to print pagination links

The pagination of a list is created using the Block Factor property, setting a number of items that you want to see in a page. The pagination is shown at runtime if the number of rows is greater than the property's value.

This is the code you need to write to print the pagination links depending on the settings chosen for the list component:

[% ...
  def firstLink = unit.selectSingleNode("layout:Link[contains(@link,'First')]") 
  def previousLink = unit.selectSingleNode("layout:Link[contains(@link,'Previous')]")
  def nextLink = unit.selectSingleNode("layout:Link[contains(@link,'Next')]")
  def lastLink = unit.selectSingleNode("layout:Link[contains(@link,'Last')]")
  ... %]
...
[% if (firstLink) { %]
  <td class="scrollText">
    <c:choose>
      <c:when test="${<wr:Id context="unit"/>.scroller.current ne <wr:Id context="unit"/>.scroller.first}">
        <wr:Link class="scroll" context="firstLink"/>
      </c:when>
      <c:otherwise>
        <span><bean:message key="PowerIndex.First"/></span>
      </c:otherwise>
    </c:choose>
  </td>
[% } %]
[% if (previousLink) { %]
  <td class="scrollText">
    <c:choose>
      <c:when test="${<wr:Id context="unit"/>.scroller.current ne <wr:Id context="unit"/>.scroller.previous}">
        <wr:Link class="scroll" context="previousLink"/>
      </c:when>
      <c:otherwise>
        <span><bean:message key="PowerIndex.Previous"/></span>
      </c:otherwise>
    </c:choose>
  </td>
[% } %]
<td class="scrollText" nowrap>${<wr:Id context="unit"/>.scroller.from} <bean:message key="PowerIndex.To"/> ${<wr:Id context="unit"/>.scroller.to} <bean:message key="PowerIndex.Of"/> ${<wr:Id context="unit"/>.scroller.of}</td>
[% if (nextLink) { %]
  <td class="scrollText">
    <c:choose>
      <c:when test="${<wr:Id context="unit"/>.scroller.current ne <wr:Id context="unit"/>.scroller.next}">
        <wr:Link class="scroll" context="nextLink"/>
      </c:when>
      <c:otherwise>
        <span><bean:message key="PowerIndex.Next"/></span>
      </c:otherwise>
    </c:choose>
  </td>
[% } %]
[% if (lastLink) { %]
  <td class="scrollText">
    <c:choose>
      <c:when test="${<wr:Id context="unit"/>.scroller.current ne <wr:Id context="unit"/>.scroller.last}">
        <wr:Link class="scroll" context="lastLink"/>
      </c:when>
      <c:otherwise>
        <span><bean:message key="PowerIndex.Last"/></span>
      </c:otherwise>
    </c:choose>
  </td>
[% } %]
  • Line 2. The Groovy scriptlet that retrieves the first link of the pagination. The expression used by the selectSingleNode() method is an XPath expression.
  • Line 3. The Groovy scriptlet that retrieves the previous link of the pagination. The expression used by the selectSingleNode() method is an XPath expression.
  • Line 4. The Groovy scriptlet that retrieves the next link of the pagination. The expression used by the selectSingleNode() method is an XPath expression.
  • Line 5. The Groovy scriptlet that retrieves the last link of the pagination. The expression used by the selectSingleNode() method is an XPath expression.
  • Lines 8-19. This section creates the "first" link of the pagination that shows the list's first page (if it is available).
  • Lines 20-31. This section creates the "previous" link of the pagination that returns to the list’s previous page (if it is available).
  • Line 32. This code shows what range of values the list displays, relative to the position in the pagination.
  • Lines 33-44. This section creates the "next" link of the pagination that allow goes to the list's next page (if it is available).
  • Lines 45-56. This section creates the "last" link of the pagination that goes to the list’s last page (if it is available).

How to print jump links

The pagination's jump link is managed using the Block Window property, setting a numerical value that specifies the maximum number of flows available to jump to the other result block.

This is the code you need to print the pagination's jump links:

[% def blockLink = unit.selectSingleNode("layout:Link[contains(@link,'Block')]") 
  if (blockLink) {%]
    <tr>  
      <td colspan="5" class="scrollText"> 
        <span><bean:message key="PowerIndex.Jump"/></span>
        <c:forEach var="current" varStatus="status" items="${<wr:Id context="unit"/>.scroller.blocks}">
          <c:set var="index" value="${status.index}"/>
          <span class="jump">
            <c:choose>
              <c:when test="${current ne <wr:Id context="unit"/>.scroller.current}">
                <a class="<wr:StyleClass context="blockLink"/> link" href="<wr:URL context="blockLink"/>"  onclick="<wr:AjaxURL context="blockLink" />">${current}</a>
              </c:when>
              <c:otherwise>
                ${current}
              </c:otherwise>
            </c:choose>
          </span>
        </c:forEach> 
      </td>
    </tr>
[% } %]
  • Line 1. The Groovy scriptlet that retrieves the pagination's block. The expression used by the selectSingleNode() method is an XPath expression.
  • Line 5. This code shows the string related to the blocks.
  • Lines 6-18. This section creates the pagination number of blocks.

How to define a Hierarchy Layout Template

Let's suppose you want to create a basic layout template for a Hierarchy Component that shows items in a hierarchical list. You can see an example of the desired graphic in the following image.

The Component Layout Information of the Hierarchy contains one <layout:Attribute> node for each Display Attribute and one <layout:Link> node for each Normal Navigation Flow as any other view component. In addition, there is a <HierarchicalIndexLevel> node for each level modeled on the component. This node may have <layout:Attribute> and <layout:Link>.

You also need to know the Component State Object's structure. See the "Hierarchy Component State Object" section of the "Component State Object" article for further information. Due to this component's complexity, the template's presentation is divided into two parts: the section related to the root level and the section related to child levels.

This is the code you need to write for printing the root level:

<c:forEach var="level1current" varStatus="level1status" items="${<wr:Id context="unit"/>.data}">
  <c:set var="level1" value="${level1status.index}" />
  <tr class="row">
    <td>
      <table cellpadding="1" cellspacing="1" width="100%">
        <wr:Iterate var="attr" context="unit" select="layout:Attribute">
           <tr>
             <th nowrap="nowrap" align="left" class="header">
               <wr:Label/>
             </th>
             <td style="padding-left:5px" align="left" class="value">
               <wr:Value item="'level1current'" position="position"/>
             </td>
           </tr>  
        </wr:Iterate> 
        <wr:Iterate var="link" context="unit" select="layout:Link[string(@sort) != 'true' and string(@scroll) != 'true']">
           <tr>
             <td nowrap="nowrap" align="left" colspan="2">
               <wr:Link class="link" position="position"/>
             </td>
           </tr>
        </wr:Iterate>
        <wr:Iterate var="hLevel" context="unit" select="HierarchicalIndexLevel">
          [% def width = 100 %]
          <tr>
            <td valign="top" colspan="2" width="[%= width %]">
              [% getSubLevelsLayout(hLevel, "level1", 2) %]
            </td>
          </tr>
        </wr:Iterate>
      </table>
    </td>
  </tr>
</c:forEach>
  • Lines 1-2. The code for printing the root level is the same as that presented for the Simple List. The only difference is the name applied to the current element, which is level1 and the name of the current iteration index variable, which is level1current.
  • Lines 6-22. Attributes and Flows are handled in a <wr:Iterate> WebRatio Generation Tag nested into the <c:forEach> tag that loops over the modeled items. Note the item and position attributes use inside tags. They are necessary to correctly identify the correspondent level.
  • Lines 23-30. The root level may have sublevels whose numbers vary. To ensure that a sublevel will show into the page, you need to manage it before closing the <c:forEach> JSTL Tag. A <wr:Iterate> WebRatio Generation Tag iterates over all the available HierarchicalIndexLevel nodes and calls the getSubLevelsLayout() Groovy function to print them.

Each Sub-Level is handled as a Simple List Component. Level depth must be handled also keeping the reference to the ancestor. The child levels can be printed one at a time if they have different layouts. If they instead have the same layout, you can use a function containing the following header:

[% 
  def getSubLevelsLayout(hLevel, position, levelCount) { 
  def currentLevel = "level" + levelCount + "current"
  def levelId = hLevel["id"]
  position = position + ",level" + levelCount
%]
// code for printing the each level
[% } %]
  • Line 2. The getSubLevelsLayout function has the hLevel variable, which is the current HierarchicalIndexLevel; the position variable that must be updated, adding the current level's new depth; and the levelCount variable, an integer counting the current depth. The function's core prints exactly the same code that the root level management prints.
  • Line 3. The currentLevel variable is used in the function body as an item for printing the values.
  • Line 4. The levelId variable is the current level's identifier.
  • Line 5. The position variable is updated adding the current level's new depth and the levelCount variable.

The body function contains the code that prints each sub level:

<c:forEach items="${level[%=levelCount - 1 %]current.[%=levelId%]data}" var="level[%=levelCount%]current" varStatus="level[%=levelCount%]status">
  <c:set var="level[%=levelCount%]" value="${level[%=levelCount%]status.index}" />
  <tr>
    <td valign="top">
      <img src="WRResources/spacer.gif" class="bullet" border="0"/>
    </td>
    <td>
      <table cellpadding="1" cellspacing="1" width="100%">
        <wr:Iterate var="attr" context="hLevel" select="layout:Attribute">
          <tr>
            <th nowrap="nowrap" class="header">
              <wr:Label/>
            </th>
            <td align="left" class="value">
              <wr:Value item="currentLevel" position="position"/>
            </td>
          </tr>
        </wr:Iterate>
        <wr:Iterate var="subLevel" context="hLevel" select="HierarchicalIndexLevel">
          [% def width = 100 %]
          <tr>
            <td valign="top" colspan="2" width="[%= width %]">
              [% getSubLevelsLayout(subLevel, position, levelCount + 1) %]
            </td>
          </tr>
        </wr:Iterate>
      </table>
    </td>
  </tr>
</c:forEach>
  • Line 1. The <c:forEach> JSTL Tag iterates over all the objects included in the current level's data property. It prints in the Web browser a row for each of the level's contained elements.

  • Line 23. The getSubLevelsLayout function has the subLevel variable, which is the current HierarchicalIndexLevel, the position variable that must be updated, adding the current level's new depth and the levelCount variable, an integer counting the current depth. The function's core prints exactly the same code that the root level management prints.

The two differences can be found in the settings of the <c:forEach> tag that must be dynamic (line 1) and the call to the Groovy "getSubLevelsLayout" function (line 23).

How to define a Form Layout Template

Let's suppose you want to create a basic layout template for a Form Component which shows to the user a two-column table. In the first column, the user sees the field label in the same row but in the second column. The table has as many rows as the number of fields. At the bottom of the table, you can see the buttons for submitting the form. You can see an example of the desired graphic in the following image. The image shows a form to manage company information.

The Component Layout Information of a form component is slightly different from all the others. In fact, you do not have any layout:Attribute elements, but you do have one layout:Field element for each modeled field. Moreover each field can have a <VRules> node containing a child for each validation rule modeled on the field.

The layout template for the form component is composed of two main parts:

The Preamble manages the Hidden Key if the Form is Entity Based, and the Core manages Fields, Hidden Fields and Flows.

This is the code you need to write for printing the fields:

<table>
  <wr:Iterate var="field" context="unit" select="layout:Field">
    <tr>
      <th valign="top" class=" header">
        <wr:Label/>
      </th>
      <td valign="top" class=" value">
        [% def fieldType = getById(field["field"])?.name
          if (fieldType == "Field") { %]
            <wr:Value class="field"/>
        [% } else if (fieldType == "SelectionField") { %]
          <wr:Value class="selectionfield"/>
        [% } else if (fieldType == "MultiSelectionField") { %]
          <wr:Value class="multiselectionfield"/>
        [% } %]
        <wr:FieldError/>
      </td>
    </tr>
  </wr:Iterate>
</table>
  • Lines 2-19. A <wr:Iterate> WebRatio Generation Tag is used to iterate over fields and prints a table column for each of them with the correspondent label.
  • Lines 8-15. A <wr:Value> WebRatio Generation Tag has different CSS classes depending on the field type used to print the layout field in the JSP page. The field's rendering is also different according to the Field type.

    The following image shows how a string field is displayed at runtime.

  • Line 16. The <wr:FieldError/> tag is used to print the eventual errors related to the current field's validation.

    The following image shows an error message of the mandatory validation rule at runtime.

How to manage an entity-based form

A modeled form can be entity-based. The most common case is a form for an entity's data management. In this case, the layout template must include a section that prints an additional hidden field containing the primary key of the object loaded in the prefilled form when it is accessed in "edit" mode. This is the code you need to add to your template:

[% if(unit["entity"] != ""){ %]
  <html:hidden property="<wr:Id context="unit"/>Key" styleId="<wr:Id context="unit"/>Key"></html:hidden>
[%}%]
  • Lines 1-3. A check is done on the entity attribute of the Component Layout Information root node to decide whether to print the additional hidden field.

How to manage hidden fields

A form may have some fields modeled as hidden. Even though those fields are not visible inside the page, they must included in the page's source code, so their value is posted with all other fields filled in by the user. This is why your template must include the following piece of code, which must not be changed.

<wr:Iterate var="hiddenField" context="unit" select="Field[@hidden='true']">
  [%  def type = hiddenField["type"]
    if (type == "blob") { %]
      <html:hidden property="[%=hiddenField["id"]%]_preload"/>
  [%  } else { %]
    <html:hidden property="[%=hiddenField["id"]%]" styleId="[%=hiddenField["id"]%]"/>
  [%  } %]
</wr:Iterate>
  • Lines 1-8. A <wr:Iterate> WebRatio Generation Tag is used to iterate over the hidden fields modeled in the form. Hidden fields are contained in the Component Layout Information as <Field> nodes having the hidden attribute set to "true".
  • Lines 2-6. The hidden field must be printed differently depending on whether it is a BLOB field. A check is done on the type, and then the field is printed out accordingly.

How to highlight mandatory fields

You may want to highlight in some way fields that have an associated Mandatory validation rule.

You can refer to the following layout template fragment to get the desired result:

def isMandatory = isMandatoryField(field)
<wr:Label> [% if(isMandatory){ %] * [% } %]
  • Line 1. Define a Groovy variable stating whether the current field is mandatory. The isMandatoryField method is a built-in Groovy method you can use for this purpose.
  • Line 2. An asterisk is printed next to the field label when the variable is true.

Common layout template improvements

This section reports a set of improvements that can be applied to the layout template regardless of their component types. It's possible to show/hide content depending on the component state object dataSize and to decide whether to print the associated frame.

How to show content only when necessary

All the templates you've seen print their HTML code without considering what is the actual component content is. If the component does not have any content to show, because it has not been computed yet or because the conditional expression matches no element, you get a page showing labels and empty values for each component property. Look at the image below for an example.

You may want to avoid this situation by adding a control that verifies the component content before printing it in the page by using the <c:if> JSTL Tag. The condition to verify is that the component state object must exist, and its dataSize must be greater than zero. The JSTL Tag must wrap all the template code that prints the component state object content.

<c:if test="${not(empty <wr:Id context="unit"/>) and (<wr:Id context="unit"/>.dataSize gt 0)}">
  //all layout template code
</c:if>

How to print the empty component message

You can decide to print a message if the component does not have any content to show, as shown in the image below.

This is the code you need to write to print the empty component message:

...
<wr:LayoutParameter label="Empty Unit Message" name="empty-unit-message" type="string" default="emptyUnitMessage"/>
...
[%
  ...
  def emptyUnitMessage = params["empty-unit-message"]
  ...
%]
...
<wr:Frame>
  <div class="plain <wr:StyleClass/>">
    <div class="plain PowerIndexUnit">
      <table>
        <tr>
          <td><bean:message key="[%printJSPTagValue(emptyUnitMessage)%]"/></td>
        </tr>
      </table>
    </div>
  </div>
</wr:Frame>
  • Line 2. Declaration of the layout parameter that defines the message's key to use if the component is empty.
  • Line 6. The emptyUnitMessage variable retrieves the message string related of the layout parameter.
  • Line 15. The <bean:message> tag retrieves a message for the specified locale, using the specified message key. The printJSPTagValue function escapes the given string value in order to be used inside a JSP tag attribute.

How to print out the frame

You can apply a Frame Layout Template to a view component from its Properties View as shown in the following image.

The frame can be a predefined one, or you can create your own as described in the "How to Define a Frame Template" article. In any case you must use the <wr:Frame> WebRatio Generation Tag to instrument the template to print the assigned Frame Layout Template. The <wr:Frame> WebRatio Generation Tag must wrap all the code that you want to be surrounded with the Frame Layout Template.

<wr:Frame>
  ...
</wr:Frame>

How to consider visibility conditions

Each model element of the Web Project can have a set of visibility conditions applied. Even if visibility conditions are modeled, you must consider them when writing your own component's layout template. This means that you must use the <wr:Visible> WebRatio Generation Tag for this purpose. You can learn more about visibility conditions and how to use them in a template from the "Getting started with Visibility Conditions" article.