Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mauserrifle's avatar

Marking list items active in blade without templates logic

I've done couple of projects using Mustache. Basically I assigned for example this to the view:

$view->categories = $categories;
$view->current_category = $current_category;

The $view object was a View Model class with a method called categories() that overruled the categories attribute. In this method the categories were marked active before returning to the template using:

foreach ($this->categories as &$category)
    $category['is_active'] = ($this->current_category['id'] === $category['id']);

The template just parsed:

{{#categories}}
<li{{#is_active}}add active class {{/is_active}}> {{name}}</li>
{{/categories}}

I am now using Blade in Laravel and am using so called Presenters for models. So that saves me from some logic. But what about collection arrays? Create special presenters for this too? It just gets a big mess with so much classes for such simple things and controllers cluttered with knowledge about what my view requires?

My blade templates now do:

@foreach ($categories as $c)
    <li><a href="{{ $c['url'] }}"@if ($c['id'] === $current_category['id']) style="font-weight: bold;"@endif>{{ $c['name'] }}</li>
@endforeach

and ugh.. I hate it. I don't want this code in my templates:

@if ($c['id'] === $current_category['id']) style="font-weight: bold;"@endif

How do you guys solve this?

0 likes
2 replies
austenc's avatar

For one, I'd recommend using a class for activation instead of an inline style. I use a couple macros for this, something like:

// Determines if menu items are active
HTML::macro('activeClass', function($pattern){
    $matched = false;

    // Force it to be an array
    if(is_string($pattern))
    {
        $pattern = (array) $pattern;
    }

    foreach($pattern as $route)
    {
        // if it's a child route or the actual route
        if(Request::is($route . '/*') OR Request::is($route))
        {
            $matched = true;
        }    
    }

    return $matched === true ? 'active' : '';

});

This is the important one

// Generates a list item with an anchor tag inside and automatically applies the active class
HTML::macro('nav', function($route, $title, $icon = null){
    if($icon !== null)
    {
        $icon = Icon::$icon();
    }

    $link = '<li class="'.HTML::activeClass($route).'">'; 
    $link .= '<a href="'.url($route).'">'.$icon.' '.$title.'</a>';
    $link .= '<li>';

    return $link;
});

I have the logic split into the two so I can re-use that activeClass macro to do activation in other cases such as submenus. I generally keep my macros in a separate file, app/macros.php and load it within the composer.json. Hope that helps!

mauserrifle's avatar

Thanks for response. It's example code. I understand classes are easier :) This really is about design concepts, not code.

As for the marco's. Not really I am looking for. What if other parts of your templates would loop categories and do something with active state? Another macro? It's silly.

With mustache I had:

Controller --> ViewModel --> template

Controller just assigned raw data to ViewModel. View model made all data as wished and templates were the dumbest ever. There wasn't much to think about design. It was perfect.

Now is:

Controller --> View/template

Presenters fix the model part. Composers fix the global part. But no fix for any other custom code such defining simple arrays for navigation etc. To me macro's just don't cut it and will avoid them at all cost.

I am missing a layer. Just like most template engines other than mustache. Anyone recognize this and made a clean solution in blade? ViewModel in between?

I really wanted to use Blade because it is convention within Laravel! Mustache is cleaner but I can live with blade if I can just fix this small issue without assigning wrappers to my view all the time.

If we could just assign a view class like:

    $view = new View_List;
    $view->categories = $categories;
    return view('list', $view);

And make this class handle it all. Blade would just read the class atributes or methods. Using macros, presenters, whatever you like. But especially being able to make simple methods like getting categories with some extra markup. For example defining a special color for category #1 and #3. It's 5 seconds work with ViewModels. I really miss this layer... :(

Help! :-)

Please or to participate in this conversation.