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.
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.
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.
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.
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/
<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>
<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>
<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?
Create another new tag
file in the tags
folder:
<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:
Replace the complete <nav>
section with the following:
#{mainmenu id:"home"/}
i.e. remove the entire <nav>
section!
#{mainmenu id:"members"/}
#{mainmenu id:"profile" /}
#{mainmenu id:"blog"/}
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.
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.
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();
}
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?
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.
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.
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.