9

I'm creating an accordion layout for an admin sidebar. Now I need to identify the active link and add a class active to that link. Here is my code:

<div class="accordion-group">
<div class="accordion-heading">
    <a href="#collapseSeven" data-parent="#side_accordion" data-toggle="collapse" class="accordion-toggle">
        <i class="icon-th"></i> Gallery Manager
    </a>
</div>
<div class="accordion-body collapse" id="collapseSeven">
    <div class="accordion-inner">
        <ul class="nav nav-list">
            <li>
                <?php echo $this->Html->link('View All',array('controller' => 'gallaries', 'action' => 'index'));?>
            </li>
            <li>
                <?php echo $this->Html->link('Add New',array('controller' => 'gallaries', 'action' => 'add'));?>
            </li>
        </ul>
        </div>
    </div>
</div>

What is the best way to do this? Thanks in advance!

lorem monkey
  • 3,942
  • 3
  • 35
  • 49
Krishna
  • 1,540
  • 2
  • 11
  • 25

5 Answers5

5

I have found the solution :

$url = $this->Html->url('INPUT_THE_URL') ;
$active = $this->request->here == $url? true: false;
Krishna
  • 1,540
  • 2
  • 11
  • 25
  • downvote, because `here()` includes all named parameters and query string. – mrdaliri Nov 10 '14 at 08:24
  • The URL in this `$this->request->here` isn't necessarily the same as the one generated by the router, even if it should be. You should normalize your URLs with [`Router::normalize()](http://api.cakephp.org/2.6/class-Router.html#_normalize) before you compare them. – bfncs Feb 19 '15 at 21:00
3

To check whether a given URL is currently active in Cakephp 2.x, you should check if it's normalized (in the sense of Router::normalize()) form is the same as the normalized form of the currently requested URL (in the sense of $this->request->here).

$currentUrl = Router::normalize($this->request->here);
$checkedUrl = Router::normalize($myUrl);
$isActive = $currentUrl === $checkedUrl;

Sometimes you might want a loose matching to show a page as active in a menu, if a child is currently shown. Think you want to display your menu link to the fruits overview site at /fruits/ as active while surfing the Banana detail site at /fruits/banana/. You can achieve this easily by looking for a partial match only.

$isActive = (0 === strpos($currentUrl, $checkedUrl));

For sure your matching might get more complex, for example if you're heavily making use of named params and the like and want to reflect it in your menu, but you should find your way from here.

A solution for your particular problem might look like this:

$currentUrl = Router::normalize($this->request->here);
$links = array(
    array(
        'label' => __('View All'),
        'url' => array('controller' => 'galleries', 'action' => 'index'),
    ),
    array(
        'label' => __('Add New'),
        'url' => array('controller' => 'galleries', 'action' => 'add'),
    ),
    /* ... */
);

foreach ($links as $link) {
    $linkLabel = $link['label'];
    $linkUrl = Router::url($link['url']);
    $linkHtml = $this->Html->link($linkLabel, $linkUrl);

    $linkActive = $currentUrl === $linkUrl;

    echo $this->Html->tag('li', $linkHtml, array(
        'class' => $linkActive ? 'active' : '',
        'escape' => false, // to not escape anchor markup
    ));
}

To make your live just that tiny bit easier by not even thinking about this question, you could also use a Helper for menu creation that someone else built like torifat/cake-menu_builder.

bfncs
  • 10,007
  • 4
  • 32
  • 52
2

There are a number of ways, here are a few for adding the class to the container

<li <?php echo ($url == 'users/account')? 'class="current"' : ''?>>
<li <?php echo (preg_match("/addresses/", $url))? 'class="current"' : ''?>>
<li <?php echo ($this->params['controller'] == 'attributes')? 'class="current"' : ''?>>

Or you can pass it into the $options

$options = array();
if($this->controller == 'mycontroller' && $this->action == 'myaction'){
  $options = array_merge($options, array('class'=>'active'));
}
echo $this->Html->link('Title', '/url', $options);
David Yell
  • 11,756
  • 13
  • 61
  • 100
  • By this approach I have to put condition on/before every link, if any helper or any other approach by which I can do it dynamically – Krishna Jul 30 '12 at 08:55
  • 2
    @Krishna this is normally the way you have to do it in PHP unfortunately, you could create your own helper class if you have a consistent layout. – Dunhamzzz Jul 30 '12 at 09:11
  • there are existing helpers etc you could use. try to google for them or search the cakephp plugins website. – mark Jul 30 '12 at 09:33
  • You could try new helpers such as this one, designed to work with the Twitter Bootstrap. https://github.com/loadsys/twitter-bootstrap-helper – David Yell Jul 30 '12 at 09:58
  • This is a really quirky and un[DRY](http://de.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself) way to get it done and you can definitely get more consistent, flexible and elegant in PHP... – bfncs Feb 19 '15 at 21:02
1

Here simple way to add active class:

<ul class="nav nav-list">
    <li class="<?php echo (($this->params['controller']==='gallaries')&&($this->params['action']=='index') )?'active' :'' ?>">
            <?php echo $this->Html->link('View All',array('controller' => 'gallaries', 'action' => 'index'));?>
    </li>
    <li class="<?php echo (($this->params['controller']==='gallaries')&& ($this->params['action']=='add') )?'active' :'' ?>">
            <?php echo $this->Html->link('Add New',array('controller' => 'gallaries', 'action' => 'add'));?>
    </li>
</ul>

I think this will helpful for you.

Krishna
  • 1,540
  • 2
  • 11
  • 25
Faisal
  • 4,591
  • 3
  • 40
  • 49
  • This approach will lead to false positives when using [prefix routing](http://book.cakephp.org/2.0/en/development/routing.html#prefix-routing), and [plugin routing](http://book.cakephp.org/2.0/en/development/routing.html#plugin-routing) as well as false negatives when you request content with other URLs than the canonical ones. Also it is very verbose and un[DRY](http://de.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself). A better approach would be checking for matching URLs after normalization with [`Router::normalize()`](http://api.cakephp.org/2.6/class-Router.html#_normalize). – bfncs Feb 19 '15 at 21:08
1

I know this is pretty old but i found a good solution.

Based on Faisal's answer i wrote my own simple Helper:

App::uses('AppHelper', 'View/AppHelper');

class PVHtmlHelper extends AppHelper {

    public $helpers = array('Html');

    public function link($title = null, $url = null, $options) {

        if ($title == null || $url == null)
            return;

        $class = (($this->params['controller']===$url['controller']) && ($this->params['action']==$url['action']) )?'active' :'';

        echo "<li class='" . $class . "'>" . $this->Html->link($title, $url, $options) . "</li>";
    }

}

Maybe you need to modify the echo <li> inside the function to fit your needs.

Example:

echo $this->PVHtml->link('Login', array('controller' => 'users', 'action' => 'login'));
q0re
  • 1,401
  • 19
  • 32
  • Thanks, that helped me a lot! =) I use CakePHP 3.1.5. So for anybody reading this, the syntax for 3.x has to be: `$this->request->params['action']`. And some differences at the beginning of the file. See: [Cakephp-3-Creating-Helpers](http://book.cakephp.org/3.0/en/views/helpers.html#creating-helpers) – eve Jan 23 '16 at 19:17