score:8

Accepted answer

Assuming you have the request object in scope, sadly enough you just need to remove the space after "if". Play templates are pretty sensitive about spacing. Try:

<div>
 @if(request.uri == "/") { "Home Menu Selected" }
</div>

score:0

To answer the question

The implicit Request, available to the templates, has all the details. Adapted to the example in the question I would use the following template function, which was tested in Play Framework 2.6. It does not require to maintain an enum but you still stay safe when updating your routes file and get compile errors when you rename the actions.

@*
  Usage:
  <div>
    @outputIf(routes.HomeController.index, "Home Menu Selected")
  </div>
*@
@outputIf(call:play.api.mvc.Call, text:String) = @{
  if (request.path.equals(call.path)) text else ""
}

Documentation

There is some documentation about reusable blocks: https://www.playframework.com/documentation/2.6.x/ScalaTemplates#Declaring-reusable-blocks

play.api.mvc.Call API: https://www.playframework.com/documentation/2.6.x/api/scala/index.html#play.api.mvc.Call

play.api.mvc.Request API: https://www.playframework.com/documentation/2.6.x/api/scala/index.html#play.api.mvc.Request

My intention (rendering Navigation)

I recently stumbled across a related Problem and after i found nothing specific to my problem on the web aside from this post, i'd like to share my final solution with you.

I'd wanted to render navigation list items with an 'active' class if the current url of the page is equal to the list items' url but neither did I like to just compare the url-string for equality as it may change and would give no compile errors - nor did I accept to create and update an enum every time I add a new navigation item (as I have an increasing amount of them including children). However I still wanted to stay safe when changing the routes urls at some time. In Play Framework 2.6 I solved the problem using this reusable function within the main.scala.html template:

@*
  Renders a list item <li> with active-class containing a link element
  Usage:
  @navItem(routes.HomeController.index, "Home")
  @navItem(routes.HomeController.index, "Home", "nav-home")
  @navItem(routes.HomeController.index, "Home", activeClass="selected")
  @navItem(routes.HomeController.index, "<span>Home</span>", "nav-home nav-element", "selected active")
*@
@navItem(call:play.api.mvc.Call, linkContent:String, cls:String="", activeClass:String="active") = @{
  val hrefAttr = "href='"+call+"'"
  val classNames = if (request.path.equals(call.path)) activeClass + " " + cls else cls
  val classAttr = if(classNames.length>0) " class='"+classNames+"'" else ""
  val linkHtml = Html(linkContent)
  Html("<li"+classAttr+"><a "+hrefAttr+">"+linkHtml+"</a></li>")
}

the comment example renders to the following in case the Homepage is requested:

<li class="active"><a href="/">Home</a></li>
<li class="active nav-home"><a href="/">Home</a></li>
<li class="selected"><a href="/">Home</a></li>
<li class="selected active nav-home nav-element"><a href="/"><span>Home</span></a></li>

score:7

What you are trying to achieve is quite common, you are trying to show the current page in a menu by marking it as active.

Solution 1

You can indeed do what you did above. Add several @if conditions with string comparisons in your template.

@if(request.uri == "/"){ class="active" }

Solution 2

But I like to go a little further in the type safe architecture. I generally create an object containing a lot of constants :

object MenuContants {
    val HOME = "HOME"
    val CONTACT = "CONTACT"
}

And then I give those constants around in the templates. From sub-template to the master layout template :

@main("The title of my page", MenuConstants.HOME) {
    // the rest of my template
}

And then in your main template, do the comparison but no longer based on strings but on constants, which is type-safe.

@(title:String, contant:String) {
    @if(contant == MenuConstants.HOME) { class="active" }
}

Related Query

More Query from same tag