Current route

Web applications have usually some kind of navigation bar (a menu). It is useful to highlight or in any other way visually distinguish currently active item from others. This short article is about determining which menu item should be highlighted.

The reasoning about this issue is hard because you have one common template with menu and you have to highlight one given <a> tag. It means, that you have to treat every possible state of that menu. Let’s look at an example, the menu that is in templates/layout.latte can simply look like this:

<nav>
    <a href="{link index}">List of persons</a>
    <a href="{link add}">Add new person</a>
</nav>

The problem is, that the menu elements does not look different whether you visit List of persons or Add new person page. But the menu is always there, so we need to cover every possible situation (i.e. the index route is active or add route is active – only one route can be active at a time). We need to build something like this to achive desired behaviour:

<nav>
    <a href="{link index}">
        {if $routeName == 'index'}
            <strong>List of persons</strong>
        {else}
            List of persons
        {/if}
    </a>
    <a href="{link add}">
        {if $routeName == 'add'}
            <strong>Add new person</strong>
        {else}
            Add new person
        {/if}
    </a>
</nav>

This template code universally highlights the menu item that currently matches some variable called $routeName. It is possible to provide this variable in every route by hand ($tplVars['routeName'] = 'currentRouteName';), but there is a better and more universal way. Slim framework provides us with request object, which also contains information about a route. You can access this object and get route name using $request->getAttribute('route')->getName() method. But again, it is tedious to do this in every route. We can use middleware mechanism of the framework to construct a new middleware which injects $routeName variable into every template and do not think about this anymore.

Middleware is a piece of code that is executed before or after a route, one middleware can be shared among many routes, better explanations and another usage of middleware is in the login article.

It is a good practice to make some effort and avoid duplication of code whenever it is possible.

To achieve this, start with modification of settings in src/settings.php file and add key called determineRouteBeforeAppMiddleware to the end of settings file:

return [
    'settings' => [
        //... some other settings ...
        'determineRouteBeforeAppMiddleware' => true,
    ],
];

Then add new middleware in src/middleware.php:

use Slim\Exception\NotFoundException;

$app->add(function (Request $request, Response $response, callable $next) {
    $route = $request->getAttribute('route');
    if (empty($route)) {
        throw new NotFoundException($request, $response);
    }
    //inject routeName to template variables
    $this->view->addParam('routeName', $route->getName());
    return $next($request, $response);
});

Presented steps are inspired by Slim cookbook article.

Summary

Now your application should highlight currently active menu item. You will learn how to make the highlight look even better in the upcoming CSS or Bootstrap article.

New Concepts and Terms

  • Current menu item/route highlight
  • Middleware

Control question

  • Is there a way to detect active route without route name?
  • Application logic is usually nested, how would you implement highlighting of nested routes?