Comparar la página actual con una ruta nombrada, en Laravel 5.2

laravel 31 de mar. de 2016

Todos sabemos que en un menú de navegación, es importante que la sección o página sobre la que estamos navegando, este diferenciada del resto aplicándole una clase distinta, por ejemplo, "active".

Ahora bien, la cosa se complica cuando el menú es común a varias páginas y tiene que saber en cuál esta para distinguirla.

Una forma es resolverlo en el cliente, usando Javascript, pero otros preferimos entregar el HTML ya formateado desde el servidor.

Para hacer esto, nuestro template Blade tiene que saber donde está y compararlo con la URL actual, para luego aplicar o no la clase correspondiente, por ejemplo:

<li @if (Request::is('/') class="active" @endif >Home</li>

Ahora bien, acá lo que hacemos es comparar directamente la ruta, pero en Laravel, tenemos la opción de nombrar nuestras rutas, y referenciarlas usando route('nombre'):

Route::get('/', '[email protected]')->name('home');

Esta ruta se puede generar mediante url('/') o mediante route('home'), ambas dando como resultado http://localhost/

Cuál es la ventaja de usar rutas nombradas, se preguntarán?

La ventaja es que si a lo largo de mi código, yo utilizo el nombre de la ruta para accederla, puedo cambiar la ruta real sin modificar el resto del código:

Route::get('home', '[email protected]')->name('home');

Los vínculos que estaban definidos con route('home') se actualizaron a http://localhost/home, mientras que los que usaban url('/') siguen apuntando a http://localhost/.

Así, logramos indepedencia de cómo se ven las rutas en el navegador y cómo las quiero definir para la estructura de mi aplicación, algo que puede ser útil, por ejemplo, para mostrar rutas en español pero accederlas desde código en inglés.

Ahora bien, que tiene todo esto que ver con el menú de navegación?

Como podrán haber imaginado, de nada sirve usar rutas nombradas, si a la hora de decidir si tengo que agregarle una clase "active" a mi ítem de menú, sigo usando la ruta directamente, en lugar de usar route():

<li @if (Request::is('/') class="active" @endif >Home</li>

Esto ya no funciona, porque ahora Home es http://localhost/home' y no es más http://localhost/.

Si tan solo tuvieramos alguna forma de usar route() para comparar contra la ruta actual...Momento, podemos!

<li @if (Request::url() == route('home')) class="active" @endif >Home</li>

De esta forma, conseguimos que la comparación sea siempre contra el nombre de la ruta y no con su dirección real.

Pero por otro lado, agrandamos bastante el código y lo complejizamos un poco, y vamos a hacer lo mismo para todas las secciones de la página!

Directivas de Blade al rescate!

Extendiendo el motor de plantillas de Laravel, conseguimos simplificar el código y dejarlo tan elegante como siempre.

<li @routeIs('home') class="active" @endif >Home</li>

Mucho mejor no?

@routeIs es una directiva de Blade que definimos nosotros, y cómo hacemos esto?
Fácil, en app/Providers/ServiceProviders abrimos AppServiceProvider:

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Blade::directive('routeIs', function ($expression) {
            return "<?php if (Request::url() == route($expression)): ?>";
        });
    }

Ahora sí! Ya podemos usar nuestra nueva directiva para fijarnos si estamos sobre una ruta nombrada o no, sin tener que usar la ruta real, ganando flexibilidad a la hora de cambiar nuestra configuración.

Espero que les haya servido!

Etiquetas

¡No dejes que nos quedemos dormidos 😴, invitanos un cafecito!

Invitame un café en cafecito.app
¡Genial! Te has suscrito con éxito.
¡Genial! Ahora, completa el checkout para tener acceso completo.
¡Bienvenido de nuevo! Has iniciado sesión con éxito.
Éxito! Su cuenta está totalmente activada, ahora tienes acceso a todo el contenido.