Skip to content

3.8.1 Template Expressions

russa edited this page Jan 15, 2019 · 10 revisions

Layout Template Expressions

Template expressions in layouts (views/layouts/*.ehtml) provide methods for generating HTML that link layouts to external JavaScript and stylesheet files. You can use these tags in layouts and even in views, although these tags are most commonly used in the <header> section of a layout. Note that the asset tag helpers do not verify the existence of the assets at the specified locations; they simply assume that you know what you are doing and generate the link.

Linking to JavaScript Files with @script

The @script expression returns an HTML script tag for the specified location. For example, to link to a JavaScript file datebox.js that is the directory content/libs/ inside of the /assets/www/ folder:

attention

@script("content/libs/datebox")


The generated script tag would be:

attention
<script type="text/javascript" src="content/libs/datebox.js">
</script>
Linking to CSS Files with @style

The stylesheet_link_tag helper returns an HTML link tag for each source provided. This helper generates a ling to /assets/www/content/stylesheets/. For example, to link to a stylesheet file main.css in the sub-directory ui_style/ located at the /assets/www/content/stylesheets/ folder, you would do this:

attention

@style("uistyle/main")


MMIR will then generate the following link tag:

attention
<link rel="stylesheet" href="content/stylesheets/uistyle/main.css"/>
Specifying Sections with @yield

Within the context of a layout, @yield identifies a section where content from the view should be inserted. The simplest way to use this is to have a single @yield, into which the entire contents of the view currently being rendered will be inserted:

attention
<html>
    <head>
    </head>
    <body>
      @yield("yield-name")
    </body>
</html> 

You can also create a layout with multiple yielding regions:

attention
<html>
    <head>
      @yield("head")
    </head>
    <body>
      @yield("content")
    </body>
</html>

The main body of the view will always render into the unnamed yield. To render contents into the @yield section, you should use the @contentFor expression in the view definitions.

View Template Expressions

Template expressions in views (views/<controller name>/*.ehtml) are used to specify the the contents of @yield sections that were declared in layouts.

In addition, several expressions allow defining dynamic content (i.e. content that is produced / modified at the time, when the view will be displayed), including control expressions like @if and @for.

Using @contentFor

The @contentFor expression is used to specify the contents that are rendered into the corresponding yield section of a layout definition. For example, the following view definition would specify contents for yield sections with the names head and content (cf. the example above):

attention
@contentFor("head"){
  <title>A simple page</title>
}@

@contentFor("content"){
  <p>Hello, MMIG! </p>
}@

The result of rendering this page into the supplied layout would be this HTML:

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
   </body>
</html>

Using multiple @contentFor expressions (in combination with the corresponding @yield sections) can help modularizing a page into distinct regions.

attention

The order in which the contentFor blocks are specified does not matter: in the example above you could also specify the contentFor "content" before the "head" – the result would be the same.

 

Using @localize

The framework allows an easy way of localization. It uses a dictionary to lookup the corresponding localized text for a supplied key:

attention
  <label for="login">
    @localize("login_label")
  </label>

Note that the language must be set and a dictionary (file) must exist, before the localization can be used properly.

On rendering, the localize expression is replaced by the corresponding value for the currently set language. In context of the StaterKit example, when the setting en as language, then example dictionary for English would be used, (cf. section Add a new Dictionary) and the result would be:

attention
  <label for="login">
    Login
  </label>
Comments @* ... *@

Comments are enclosed by @* and *@. Comments will not be displayed in the rendered view in any way. All content that is within a comment section is not processed by the parser and will be removed before the view is rendered.

A little example the comments statement in action:

attention
<html>
   <head>
     @* Here comes the title of the view *@
     <title>A simple page</title>
   </head>
   <body>
     @* and here is the body contents *@
     <p>Hello, MMIG! </p>
   </body>
</html>

This will result in:

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
   </body>
</html>

The contents of the comments statements is simply removed.

The comments expression can also be used for (temporarily) disabling template expressions: attention

...
	<div>Upcoming events:
     @* not implemented yet: @render('Calendar', 'my_time_table') *@
     @( MY_DUMMY_DATA.timeTableStub )
    <div>
...
     

Template Dynamic/Code Expressions

Dynamic template expressions are evaluated immediately before the view will be displayed.

Using template variables @var

Template variables can either be displayed in the view (cf. section Rendered javascript) or manipulated inside a JavaScript code segment – see following sections. The access to the variable is limited to the surrounding contentFor block of the view (see section Using @contentFor). If the variable is used within a partial, it is accessable throughout the whole partial as a partial is an implicit contentFor section.

attention
@var(title_string)
@{@title_string = "Title String"}
<html>
   <head>
     <title>@(@title_string)</title>
   </head>
   <body>
     <p>>@(@title_string)</p>
   </body>
</html>

The use of @var and the @ prefix makes the variable's scope local for this template. This also means that no global variable with the same name is overwritten or the value from a global variable is used instead of a local created variable.

The variable will only be replaced by its value on rendering, if it is used inside a (rendered) javascript section – see section Rendered javascript code @( ... )). Simply adding @variable to a view will just result in rendering @variable at this position – instead of the value of var.

attention

If a variable is used inside a javascript code block (unrendered or rendered), it should be initiated with @var() and referenced with @ to ensure that the variable is not overwriting a global variable.

Note that variables are not permitted inside a layout description.

Script Blocks @{ ... }@ (not rendered)

This expression evaluates the containing javascript code but does not render the return value. Inside the code block standard javascript can be used. See also the section about variables for a brief explanation about the scope of variables.

The following snippet is an example of how to use the unrendered javascript code:

attention
@{@page_name = "simple page";}@

@{
   @dots="";
   for (@i = 0; @i < 30; @i = @i + 1){
      @dots = @dots + ".";
   }
}@
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
   </body>
</html>

The first line simply assigns a value to the variable page_name. The section beginning on the second line creates a string with 30 dots. All these commands are simply executed, but nothing is rendered for it in the final view. So the rendered, it will just look like this:

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
   </body>
</html>
attention

Note that the un-rendered javascript code block can contain multiple lines of code.

 

 

Script Statements @( ... ) (rendered)

This expression evaluates the containing javascript code and displays the return value into the location of the template expression. Inside the code block standard javascript can be used. See also the section about variables for a brief explanation about the scope of variables.

This example shows the usage of a rendered javascript code:

attention
@{@page_name = "simple page";}
<html>
   <head>
     <title>A simple page with the name @(@page_name)</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
   </body>
</html>

The variable page_name is replaced with the string assigned to it, resulting in the following code:

attention
<html>
   <head>
     <title>A simple page with the name simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
   </body>
</html>

As seen above, this construct is used to display template variable values.

attention

Note that the rendered javascript code block cannot contain multiple lines of code – it is mainly used for the display of template variables. In contrast, the unrendered javascript code can contain multiple lines of code.

 


Template View/Controller Expressions

Calling a helper function @helper

If a helper method is defined for a controller, it can be called from within a view. The helper's return value is then rendered into the view at the position of the helper call.

The syntax of the helper call is:

@helper(functionName : String [ , data : <String|Number|Boolean|PlainObject> ])

The first argument functionName is the name of the helper function. The controller need not to be specified: the helper expression always refers to current view's controller. The helper function can be called with an optional data argument.

When the view is rendered, the helper method is invoked and its return value will replace the template expression in the rendered view.

attention

If a data argument is passed to a helper function via the helper call, this data can be accessed inside the helper function by using the arguments variable. The arguments variable holds data-argument of the helper call at the 3rd position:
function the_helper_function(ctrl, viewData, data)

(for more detials see section Accessing data arguments)

This snippet calls a helper method named createListElements with {obj1 : 'value1', obj2 : 'value2'} as data argument and renders the return value in place of the helper expression:

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
     @helper('createListElements', 
             {obj1 : 'value1', obj2 : 'value2'})
   </body>
</html>
Rendering a partial view @render

Using a partial expression @render in a view, will evaluate the partial's definition and render its result in place of the @render statement.

The syntax for the @render statement is:

@render(controllerName : String, partialName : String [ , data : <String|Number|Boolean|PlainObject> ])

The controllerName is the name of the controller which is associated with the partial, and partialName is the name of the partial.

Note that partial definitions from any view can used; the @render statement is not restricted to the current view's controller. This allows to specify re-usable "template-snippets" across controllers.

The data argument allows for the passing of arguments to the partial, e.g. ascertained by a helper method. The type of the data argument can be one of the following: a string / number literal, template variable or a JSON like object, which itself can consist of an array, string / number literal and a JSON like object.

attention

If a data argument is passed to a partial via the render call, the data can be referenced inside the called partial by using the @argument variable. This variable holds the arguments of the render call.

 

For example, the following render expression would render the partial definition in file ~languageMenu.ehtml of the Application controller. The (optional) data argument can be accessed from within the partial defintion via the @argument expression.

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
     @render('Application', 'languageMenu',
              {displayTitle : true, salutation : "Bob"})
   </body>
</html>

Inside the partial definition for languageMenu, the data argument {displayTitle : true, salutation : "Bob"} can be referenced via the @argument variable (cf. Accessing data arguments).


Template Control Expressions

Template control expressions let you manipulate the control flow for rendering a view: they control / modify if and how a view will be rendered.

TBD: add details and examples for template expressions (see example for partial in /views/application/~languageMenu.ehtml).

Conditional rendering @if

For the control of the rendered view output, the @if construction can be used to display parts of the code only if a defined condition is true.

The syntax is:

@if (javascript condition) {
  part to display if condition is true – view expressions or HTML
}@ [ @else{ 
  part to display if condition is false – view expressions or HTML 
}@ ]

The else-part is optional. Inside the if segments all view expressions, including HTML, can be used.

An example of a conditional rendering:

attention
@{@debug = true;}
<html>
   <head>
     @if(@debug == true){
       <title>Debug mode</title>
       @{@debug_time = new Date();}
     }@ @else {
       <title>A simple page</title>
     }@
   </head>
   <body>
     <p>Hello, MMIG! </p>
     @if(@debug == true){
     <div id="debug_info"></div>
     }@
   </body>
</html>

This would result in the rendered view:

attention
<html>
   <head>
       <title>Debug mode</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
     <div id="debug_info"></div>
   </body>
</html>
attention

The if statement can be used hierarchically – just like in javascript.

 

 

Loops with @for

For the generation of similar view sections, e.g. menu items, the @for statement can be used. The @for statement has two versions:

  1. using counter variable
  2. or for iterating over an object's properties

The syntax is:

@for (initialization; condition; incrementStatement) { 
  loop body 
}@

or:

@for (propertyName in object) {
  loop body
}@

The following snippet creates a list of the work days of the week by using a counter:

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
     @{ @daysArray = ["mon", "tue", "wed", "thu", "fri"]; }@
     <ul>
     @for(@i=0, @size = @daysArray.length; @i < @size; ++ @i){
        <li>@(@daysArray[@i])</li>
     }@
     </ul>
   </body>
</html>

The results is:

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
    <ul>
        <li>mon</li>
        <li>tue</li>
        <li>wed</li>
        <li>thu</li>
        <li>fri</li>
     </ul>
   </body>
</html>

Alternatively, the same can be achieved by using the iterative version of the @for statement as follows:

attention
<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
     @{ @daysArray = ["mon", "tue", "wed", "thu", "fri"]; }@
     <ul>
     @for(@i in @daysArray){
        <li>@(@daysArray[@i])</li>
     }@
     </ul>
   </body>
</html>

Special Statements

Escaping the at sign @@

If the at sign, @ itself has to be displayed in a view, it must be "escaped" by second @:
@@ will be rendered to @.

For example, in a template file:

@if( @data.email ){
	<div>e-mail: some@@mail-address.com</div>
}@

will be rendered as

	<div>e-mail: some@mail-address.com</div>

(that is, if the templae's @if expression is evaluated to true)

Accessing data arguments

The expressions for helper functions, as well as the expression for rendering partials, allow to for a data argument:

@helper('function_name_within_the_helper', data)

and

@render('controller_name','partial_name', data)

This data arguement can be accessed in the helper function - or partial definition - through the arguments variable (helper function), or using the @argument expression (within the partial's template definition) respectively.

For example, within a partial definition, data argument {some: 'data'} can be accessed via the @argument variable:

attention

<div>
  The supplied arguments are: @(JSON.stringify(@argument.some))
</div>


As for accessing the data argument from the helper function implementation: here, the signature for a helper function actually takes three arguments:

  1. the controller name controller of the helper (ctrl)

  2. the data argument, that is used for rendering the view (viewData)
    this is the data-argument from the context where the helper expression itself is used, i.e. the optional data-argument for the render-function of the PresentationManager, e.g. mmir.dialog.render('Application', 'login', viewData)

  3. the data argument used in the helper expression (callData)
    this is the data-argument that is specfied in the helper expresson, e.g. @helper('function_name_within_the_helper', callData)


So for example, within the helper function, the data argument {some: 'data'} from the helper expression can be accessed via the 3rd position in the arguments variable:

attention
function function_name_within_the_helper(ctrl, viewData, callData){
	
	//accessing the call-data by name
	// (as specified in the function's definition)
	if(callData.some === 'data'){
   		// do something
	}
	
	//... or generically via arguments:
	if(arguments[2].some === 'data'){
   		// do something
	}
}
Rendering data @data

If a call to render a view is also supplied with arguments, these can be accessed with the @data template variable. Calls to render views are typically generated by the state machine and can be supplied with additional parameters to create contextual rendered output.

A call to render the loginManager view may look like this:

attention
mmir.dialog.render(
  'Application', 'login', {languageMenu : true}
);

Inside the view login, the property languageMenu can be accessed by referencing to @data.languageMenu, which will yield true.


< previous: "Application Views" | next: "Setup MMIR for Internationalization" >

Clone this wiki locally