Objectives

The play framework has a feature call 'Tags' which offer a more sophisticated mechanism for aggregating view from multiple elements. This lab will explore this feature in detail, and conclude with an exercise inviting you to create your own tag.

Settings Menu

The starting point of this lab is the solution from the previous lab:

Introduce a new settings menu, which is to be a drop down on the far right of the menu bar. The drop down is to have a 'logout' and a 'settings' menu item.

Settings

Create a new folder called tags in the views folder. In this folder create a file called settings.html

  <div class="right menu">
    <div class="ui dropdown item">
      <i class="user icon"></i>
      <div class="menu">
        <a class="item" href="/editprofile">Settings</a>  
        <a class="item" href="/logout">Logout</a> 
      </div>
    </div>
  </div>

This is a new menu, which we will incorporate into our menus.

main.html

In views/main.html, incporprate the following before closing <body> tag:

    <script>
      $('.ui.dropdown').dropdown();
    </script>

This script is necessary to enable the drop down capability of the menu.

Menu Changes

For each of the <nav> sections in each of the pages, we will need to include the above menu. Note that we also delete the existing 'logout' link in each nav/

views/Home/index.html

<nav class="ui inverted menu">
  <header class="header item"> Spacebook </header>
  <div class="right menu">
    <a class="active item" href="/home">Home</a></li>
    <a class="item" href="/members">Members</a>
    <a class="item" href="/profile">Profile</a>
    <a class="item" href="/blog">Blog</a>
    #{settingsmenu /}
  </div>
</nav> 

views/Members/index.html

<nav class="ui inverted menu">
  <header class="header item"> Spacebook </header>
  <div class="right menu">
    <a class="item" href="/home">Home</a></li>
    <a class="active item" href="/members">Members</a>
    <a class="item" href="/profile">Profile</a>
    <a class="item" href="/blog">Blog</a>    
    #{settingsmenu /}
  </div>
</nav> 

views/Profile/index.html

<nav class="ui inverted menu">
  <header class="header item"> Spacebook </header>
  <div class="right menu">
    <a class="item" href="/home">Home</a></li>
    <a class="item" href="/members">Members</a>
    <a class="active item" href="/profile">Profile</a>
    <a class="item" href="/blog">Blog</a>    
    #{settingsmenu /}
  </div>
</nav> 

Finally, we remove the 'Edit' button from the components/profileimages.html component:

  <a href="/editprofile" class="ui button"> Edit </a>

(delete the above)

What we have implemented above is an example of Tags:

Contrast this approach with the 'include' mechanism we have been using to aggregate templates. Can you see the (minor) differences?

mainmenu Tag

Create another new tag file in the tags folder:

views/tags/mainmenu.html

<nav class="ui inverted main menu">
  <div class="title item"> Spacebook </div>
  <a id="home"    class="item" href="/home">Home</a>
  <a id="members" class="item" href="/members">Members</a>
  <a id="profile" class="item" href="/profile">Profile</a>
  <a id="blog"    class="item" href="/blog">Blog</a>
  #{settingsmenu /}
</nav> 

<script>
  $("#${_id}").addClass("active item");
</script>

This is a new smart tag - which can accept a parameter. In this case, the parameter _id will be the active menu item. We can now significantly simplify all the menu sections of the views:

views/Home/index.html

Replace the complete <nav> section with the following:

#{mainmenu id:"home"/}

i.e. remove the entire <nav> section!

views/Members/index.html

#{mainmenu id:"members"/} 

views/Profile/index.html

#{mainmenu id:"profile" /}

views/Blog/index.html

#{mainmenu id:"blog"/} 

statusupdate Tag

You may have noticed that when we update the status from the home page - we are taken to the Profile page when you submit the change. This is an anomaly, which is unavoidable due to the way we have currently implement the feature. We will try to fix that here.

conf/routes

First some a new route:

POST    /home/changestatus                      Home.changeStatus

Which will be another way of changing the status - this time implemented in the Home controller.

controllers/Home.java

The new method to service the above route:

  public static void changeStatus(String statusText)
  {
    User user = Accounts.getLoggedInUser();
    user.statusText = statusText;
    user.save();
    Logger.info("Status changed to " + statusText);
    index();
  }

Views/taga/statusupdate.html

Create a new tag:

<section class="ui stacked segment">
  <h4 class="ui inverted red block header"> Status</h4>
  <div class="ui message">
    <p> ${_status} </p>
  </div>
   <section class="ui form segment">
    <form action="${_route}" method="POST">
      <div class="field">
        <textarea name="statusText"></textarea>
      </div>
      <button class="ui button teal submit labeled icon"><i class="icon edit"></i> Update </button>
    </form>
  </section>
</section>  

Notice in the above we are expecting the route to be in _route - and this is what we use in the action of the form?

Views/Home/index.html

Finally, in the Home view, we engage this tag (instead of including the component)

      #{statusupdate route:"/home/changestatus", status:"${user.statusText}" /} 

You should be able to put all these pieces together now and test.

Exercises

Exercise 1:

Views/Home/Profile currently contains this include:

      #{include "components/statusupdate.html" /}   

Replace it with the appropriate use of the tag developed in the last step. You should be able to remove the components/statusupdate.html file when this is completed.

Exercise 2:

Develop a new tag called 'profileimage'. The purpose of this tag is to encapsulate the image upload feature. It is to be included by the Home and Profile views, so that the same tag can be used from those views. Use the structure of the statusupdate tag for inspiration.