Chapter 4. Exploring Views

Views are an essential part of an application, or, in cases where interaction is minimal, they are the means to show what an application is capable of. They have the power to increase the number of end users or discourage them completely. Views that enhance the user experience are always preferred over those that are as complicated as a maze, through which the user struggles to perform a simple task. They act as a deciding factor in an application's success.

In this chapter, we will cover the following topics:

  • Building views using Twirl
  • Generating Form
  • Internationalization
  • Templating Internals (covers basics of how Twirl works)

Diving into Scala templates

A Twirl template is composed of parameters and content. The following figure shows the components of a login page template called login.scala.html:

Diving into Scala templates

Note

The parameters must be declared first since they are used as the parameters of the apply method of the generated template object. For example, for the main.scala.html template, shown in the preceding code, the apply method will be:

def apply/*1.2*/(title: String)(content:play.api.twirl.Html):play.api.templates.HtmlFormat.Appendable = {...}

The template content can be HTML as well as Scala code.

For example, let's look at some defaultpages (accessible through the object views.html.defaultpages) bundled along with Play. The default view for this action is not implemented; todo.scala.html has no template parameters and has plain HTML for its content. It is defined as follows:

<!DOCTYPE html>
<html>
  <head>
    <title>TODO</title>
    <link rel="shortcut icon" href="data:image/png;base64,iVBORw..">
    <style>
    ...
    </style>
        
  </head>
  <body>
    <h1>TODO</h1>

    <p id="detail">
      Action not implemented yet.
    </p>

  </body>
</html>

Similarly, the default view for unauthorized, unauthorized.scala.html, is also a static page.

Now, let's check how the view for action not found in development mode, devNotFound.scala.html is defined:

@(request:play.api.mvc.RequestHeader, router:Option[play.core.Router.Routes])

<!DOCTYPE html>
<html>
  <head>
    <title>Action not found</title>
    <link rel="shortcut icon" href="data:image/png;base64,iVBORw..">
  </head>
  <body>
    <h1>Action not found</h1>

    <p id="detail">
      For request '@request'
    </p>

    @router match {

      case Some(routes) => {
    
        <h2>
          These routes have been tried, in this order:
        </h2>

                <div>
    @routes.documentation.zipWithIndex.map { r =>
      <pre><span class="line">@(r._2 + 1)</span><span class="route"><span class="verb">@r._1._1</span><span class="path">@r._1._2</span><span class="call">@r._1._3</span></span></pre>
    }
	             </div>

      }

      case None => {
        <h2>
          No router defined.
        </h2>
      }

        }

  </body>
</html>

In the template snippets, the style component has been excluded to focus on the Scala code used.

If there is a route file defined, then it lists all the available routes in a preformatted block. The methods defined for the type of the template parameter can be called even within the template. For example, if books: Seq[String] is one of the parameters, we can call @books.length or @books.map{...}, and so on, within the template.

Additionally, a Twirl template can be used within another template. This allows us to have reusable chunks of views. For example, supposing we have a main template, which is used by all other views, the application's theme (which includes the header, footer, basic layout, and so on) can be updated by tweaking the main template. Consider a template main.scala.html, defined as follows:

@(title: String)(content: play.twirl.api.Html)

<!DOCTYPE html>

<html>
    <head>
      <title>@title</title>
    </head>
    <body>
    <header>brand name</header>
    @content
    <footer>Copyright 2013</footer>
    </body>
</html>

Reusing this template will be as simple as the following:

@main("locate us"){
  <div>
    company address
  </div>
}

Another example is defining widgets as templates. These widget templates can then be used in multiple views of the application. Similarly, we can also define code blocks within our templates.

Building a view

Let's build a view, which is commonly found in today's web applications. A view where the user is asked to select the account they want to log in with, such as Google, Facebook, and so on, is given a list of providers with the condition that, by default, the first provider should be selected.

Consider that in the list of supported third-party authentications, otherAuth is passed as a template parameter. The type of otherAuth is Seq[ThirdPartyAuth], where ThirdyPartyAuth is a case class defined to represent any third-party authentication API.

So, this is completed as follows:

<div>
    <p>
      Please select the account you wish to use

      @for(auth <- otherAuth) {
        <input type="radio" name="account" value="@auth.id"> @auth.name
    <br/>
        }
    </p>
</div>

In this snippet, we used for to iterate through all the supported third-party authentications. In the templates, we can use two Scala functions, for and if, in addition to those defined within the template and the ones defined on the basis of the type of template parameters.

Now, the only important part remaining is to set the default value. We can achieve this by using one of the utility methods provided by Twirl the defining method. Let's create a variable to check whether the provider is the first one or not. We can then have different markups for the two possibilities. If we modify our code to accommodate this, we will get this code:

<div>
    <p>
        Please select the account you wish to use

        @for(auth <- otherAuth) {
            @defining(auth.id == otherAuth.head.id) { isChecked =>
                @if(isChecked) {
                    <input type="radio" name="account" value="@auth.id" checked="checked"> @auth.name
                    } else {
                    <input type="radio" name="account" value="@auth.id"> @auth.name
                    }
            }
        <br/>
        }
    </p>
</div>
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.163.250