Community contributed extensions

Navigation Module

The navigation module allows you to easily define and use a navigation menu in your Play project.

Quick Start

  1. Add the navigation module to your dependencies.yml file
  2. Define a navigation structure in conf/navigation.yml, see sample
  3. Add @ With(MenuInjector.class) to your controllers
  4. Display the menu in your template with #{navigation.default mainMenu /}

Less Quick Start

Introduction

The navigation module allows you to define a navigation structure for your website, and show one or more menu’s on your page, based on this structure. There are three staps that need to be taken to integrate a menu in your site. First, the navigation structure must be defined, second the navigation structure must be retrieved and context must be added and finally it must be rendered.

The navigation module keeps your navigation structure in memory, so no database access is needed to show a menu, making it fast and simple.

Defining your navigation structure

The navigation structure is defined in a file navigation.yml, that resides in your conf directory. As you might have guessed, this is a YAML file. A menu structure is a tree: you have one root node, and each node can have zero or more children. A node in the navigation structure is a MenuItem. See sample for an example of a navigation structure.

A MenuItem has the following properties:

FieldTypeDescription
parentYAML ReferenceReference to the parent node
textStringThe link text for the menu item
actionStringThe action this menu item links
urlStringThe url this menu item links, if action is not specified
labelListA list of strings, you can hide or show menuitems based on these labels, for example 'admin'
paramsMap<String,String>A map from strings to string, which will become the parameters for the action that is called
propertiesMap<String,Object>A map of custom properties you can add to your menuItem. An example is to add an extra class to a certain menu item, or specify a background image. You can retrieve these properties in your renderer.

Get menu and add context

A menu can not be built from only the structure. The context in which it appears can change how the menu must be rendered. For example if you are viewing the products page, the corresponding menu item shoud be highlighted as being the currently active menu item. Also, you might want to show only the submenus of the currently active menu.

To get a menu, use the following code from a Controller: ContextedMenuItem menuItem = Navigation.getMenu(name), where name is the name of the root element, which is ‘main’ in the sample navigation.yml. The root element itself will not be shown, but its children form the menu. So on a regular site, you could have a root menu item called main, and children like home, products, cart, contact, etc. Each of this children could have children of its own.

You usually want the menu button that is currently active (e.g. the products button when you are on the products page) to be shown differently. In the navigation module, this is called active. If your menu is multiple levels deep, you might also want to treat the items higher in the hierarchy to show up differently. If the garden products menu item is active, and it is a child of the products menu item, you might want both of them to be highlighted. The navigation module also allows to to check for every menu item whether it has an active child.

Any menu item whose action field is set to the action that is being invoked by play will be automatically set as being active. This works in the majority of cases, but sometimes you want more control. You could for example have a products search page, with both a Products.showSearchForm and a Products.showSearchResults action, with the search menu item action set to Products.showSearchForm. Now, if your search results are displayed by the Products.showSearchResults action, the search menu item would not be marked active, since the action doesn’t match the invoked action. To remedy this, you can set an @ ActiveNavigation("Products.showSearchForm") annotation on the Products.showSearchResults action. This will cause the search menu item to be marked as active.

If you want to programmatically set the active action you can use the methods on the MenuContext available from ContextedMenuItem.menuContext.

Finally, we must add the menu to the renderArgs. This can be done manually, with renderArgs.put("mainMenu", Navigation.getMenu("main")), but you can also use the MenuInjector controller, which has an @ Before annotation. To use this method, add @ With(MenuInjector.class) to your controller. The MenuInjector can be configured through the application.conf file; you can set which menus it must inject in your renderArgs automatically with the navigation.defaultMenus property.

Rendering

In your view, you now have a mainMenu variable. You can render a menu using #{navigation.default mainMenu /}

The default renderer renders your menu as nested &lt;ul&gt;'s and &lt;li&gt;'s. It has some options:

Option nameDefaultExplanation
showLevels99The maximum number of levels the menu must show. You can use this to only show the top level entries for example, by setting this to 1
expandLevels99Which levels must always be expanded. Levels below this will only be expanded when their parent item is active

You can easily change the way of rendering by copying the default tag into your project and modifying it to your liking.

More

Accessing the MenuContext

If you use the MenuInjector, the MenuContext is hidden from you. You can still retrieve it in your actions:

MenuContext context = ((ContextedMenuItem)renderArgs.get("mainMenu")).menuContext;

Alternatively, you can decide not to use the MenuInjector, and inject the menu yourself. It is a simple oneliner, see the MenuInjector source for details.

Getting the MenuContext is useful if you want to use labels, programmatically set the active action, or if you want to set params.

Using labels

If you add labels to a MenuItem in your navigation.yml file, the MenuItem will only be visible if you add at least one of those labels to the MenuContext, with addActiveLabel(String label). You could add an ‘admin’ label for example, and only activate this label for users with admin permissions in an @ Before interceptor.

Using params

See next section, using sample app. This will be documented properly in the future.

Sample app

To run the sample application demo, enter the samples-and-tests/demo directory, and run play dependencies (this only works with Play 1.2 and up, and then play run. Also check out the source of this demo, as it uses some undocumented features like variable substitution.