Skip to content

3.8. Project Structure # Application Views

dfki-flpe edited this page Aug 1, 2014 · 1 revision

Application Views (www/views)

This folder contains the views of MMIR applications. Each controller can have a set of views which will be rendered by the PresentationManager. The view definitions will be loaded automatically when the application is started. Additionally to the specific views, there is a folder containing the layout definitions. The MSK has one layout (application.ehtml) which belongs to the Application controller. This layout must exist, as it is used as default fallback: In General, each controller can have its own layout (but only one layout per controller) which is used when rendering the views of this controller. If there is no specific layout defined for a controller, the Application layout is used by default.

Structuring Views

In MVC based architecture, the view component is responsible for presenting the data to the user in a way that is "palatable" to the user, abstracting from the unnecessary details. In other words, any framework implementing and supporting the MVC pattern should provide means for to ease abstraction and presentation of the required data. This is also true for the MMIR framework, which follows the MVC pattern. The view definition should provide all necessary services for building a dynamic View component. The following are the main services provided by the views:

  • Layout (will be described below)
  • Templates (the views and partial views; will be described below)
  • View Helpers (see chapter Application Helpers (www/helpers), p. 13)
attention > **Layout vs. View vs. Partial** > > The main concept for displaying content to the user (i.e. the GUI) is the view. Layouts and partials can be considered "helper constructs" that assist in rendering the view for display to the user.| > > The main differences between layouts, views, and partials are notably: > > Layouts: are used to specify the "skeleton" for all views of a controller. The layout contains the static, non-changing content that stays the same for all views, and the layout contains the `@yield` declarations, which are named section-declaration that will be "filled in" by the specific view's `@contentFor` definitions. > > **Located**: /views/layouts/[controller-name].ehtml > > Views: specify the content that should be filled into the layout's `@yield`-sections; i.e. the content that is specified with the `@contentFor` expressions is rendered into the corresponding `@yield` sections of the view's layout. In difference to layouts, views can contain various template expressions for dynamically creating content, e.g. `@for`, `@if`, `@{code}@`, … > > NOTE: content in a view that is not specified within a `@contentFor` expression will be ignored when rendering the view into its layout. > > **Located**: /views/[controller-name]/[view-name].ehtml > > Partials: are usually small "partial content" definitions (e.g. for re-usable content definitions) that are rendered "as-is", i.e. partial templates do not use `@contentFor` section definitions (as views do), but instead all the partial's content is rendered into the referring view. A partial can be included into a view by using the `@render` expression. > > NOTE: the file-names of partials are prefixed with `~` (tilde). However, when referring to partials (e.g. using the `@render` expression) this character is omitted. > > **Located**: /views/[controller-name]/~[partial-name].ehtml

Structuring Layouts

When MMIR renders a view, it does so by combining the view with the controller's layout. If the controller has no specific layout defined, the Application layout will be used instead. For defining layouts, you have access to 2 template expressions:

  • Asset tags (i.e. template expressions @script and @link)
  • Yield tags (i.e. template expression @yield) Note that in views (and partials) additional template expression can be used, see section View Template Expressions (p. 17).

Layout Template Expressions

Template expressions in layouts 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 each source provided. This helper generates a link to /assets/www/libs/. For example, to link to a JavaScript file that is inside a directory called datebox inside of the /assets/www/libs/ folder, you would do this:

@script("datebox/jpath")

MMIR will then output a script tag such as:

<script src='/libs/datebox/jpath.js' type="text/"></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 that is inside a directory called ui_style inside of the /assets/www/content/stylesheets/ folder, you would do this:

@style("ui_style/main") 

MMIR will then generate the following link tag:

<link rel="stylesheet" hred="content/stylesheets/ui_style/main.css"/>
Understanding @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:

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

You can also create a layout with multiple yielding regions:

<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 content into a named yield, you should use the contentFor method in your view definition.

View Template Expressions

Using @contentFor

The contentFor method allows you to insert content into a named yield block in your layout. For example, this view would work with the layout that we just saw:

@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:

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

The contentFor method is very helpful when your layout contains distinct regions such as headers and footers that should get their own blocks of content inserted.

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:

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

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

On rendering the localize part is replaced by the corresponding value for the currently set language. For the setting en as language and an example dictionary, presented in section Add a new Dictionary, the result would be:

  <label for="login">
    Login
  </label>
Commentary @* … *@

Commentary is surrounded 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 of a commentary in action:

<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:

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

The commentary is simply removed.

Template Dynamic/Code Expressions
Using template variables @var

Template variables can either be displayed in the view (see 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.

@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.
Unrendered javascript code @{ … }

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:

@{@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 those commands are simply executed and nothing is going to be rendered in the final view. It will just look like this:

<html>
   <head>
     <title>A simple page</title>
   </head>
   <body>
     <p>Hello, MMIG! </p>
   </body>
</html>
attention > Note that the unrendered javascript code block can contain multiple lines of code.
Rendered javascript code @( … )

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:

@{@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:

<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 [, params])

The function name is the name of the helper function. No controller has to be supplied – it is always the controller of the current view. The helper call can also be supplied with arguments via params.

As the view is rendered, the helper method is called and its return value embedded in the currently processed view.

attention > If a `params` argument is passed to a helper method via the `helper` call, the data can be referenced inside the called helper by using the `arguments` variable. This variable holds the arguments of the helper call.

This snippet calls a helper method named createListElements with some arguments and puts the return value in place of the method call:

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

To insert a partial anywhere in the view, the @render statement is used. This processes the referenced partial and displays the rendered result at the position of the call.

The syntax for the @render statement is:

@render(controllerName, partialName, data)

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

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.

This render call of a partial may display a menu to select a language and supply a title as well as a personal salutation to the user:

<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 languageMenu, the data of the render call, {displayTitle : true, salutation : "Bob"}, may be referenced via the @argument variable.

Template Control Expressions

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:

@{@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:

<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 can be used in two ways: to iterate over an object or it is used as a counter.

The syntax is:

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

@* or: *@

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

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

<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>

This results in:

<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>

The same can be achieved by using the iterative way of the @for statement:

<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

At sign @@

If the at sign, @, should be displayed in the view, it must be "escaped" by another @: @@ will display @.

Accessing function arguments @argument

Inside a called helper function or rendered partial, the supplied data can be referenced by either referencing the arguments variable inside the helper function or referencing the @argument template variable inside a partial.

A partial can reference the supplied arguments easily with the @argument template variable:

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

Inside a helper function, the supplied arguments can be referenced by the arguments variable:

var args = arguments;
for (var a in args){
   // process the arguments
}
Render 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:

dialogManager.render('Application', 'login', {languageMenu : true});

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

Clone this wiki locally