yii2
yii2 copied to clipboard
Menu parent active status gets broken for the rest of the items when using Closure for one item
Possibly related to:
- #15657
What steps will reproduce the problem?
- Create a menu with
yii\widgets\Menu
- Use
Closure
to determine if one item isactive
- That item works correctly, including its parent
- But, when you now click on another item, the item gets active, but not its parent
Open your views\layouts\main.php
and put this code inside at the top:
<style>
.nav li.active > span {
color: red;
}
.nav li.active > a {
color: red;
}
</style>
<div style="border: 1px solid red; padding-top: 100px;">
<?php
echo yii\widgets\Menu::widget([
'options' => ['class' => 'nav nav-pills nav-sidebar flex-column'],
'linkTemplate'=>'<a class="nav-link" href="{url}"> {label}</a>',
'labelTemplate'=>'<span>{label}</span>',
'itemOptions'=>['class' => 'nav-item'],
'activateParents' => true,
'items' => [
['label' => 'Home', 'url' => ['/site/index']],
['label' => 'About', 'url' => ['/site/about']],
[
'label' => 'Parent menu item',
'items' => [
['label' => 'First child active auto', 'url'=> ['//site/first-child']],
[
'label' => 'Second child active by Closure',
'url'=> ['//site/second-child','run'=>1],
'active'=> function ($item, $hasActiveChild, $isActive, $menuWidget) {
if (Url::current()==Url::to(['//site/second-child'])) {
return true;
}
return false;
},
],
]
],
],
]);
?>
</div>
Then open your SiteController
and add these two actions:
<?php
// ...
public function actionFirstChild()
{
return $this->render('index');
}
public function actionSecondChild($run=0)
{
if ($run) {
return $this->redirect(['second-child']);
}
return $this->render('index');
}
What is the expected result?
- The parent item to be activated too when clicking items that don't use the Closure
What do you get instead?
- Only the child item gets activated, but not its parent, when you click the child that doesnt use Closure
- But the child with the Closure works properly
Additional info
Q | A |
---|---|
Yii version | 2.0.43 |
PHP version | 7.3.6 |
Operating system | Windows 10 |
Possible solution
Open https://github.com/yiisoft/yii2/blob/master/framework/widgets/Menu.php#L285 and change this:
<?php
} elseif ($item['active'] instanceof Closure) {
$active = $items[$i]['active'] = call_user_func($item['active'], $item, $hasActiveChild, $this->isItemActive($item), $this);
}
With this:
} elseif ($item['active'] instanceof Closure) {
if (call_user_func($item['active'], $item, $hasActiveChild, $this->isItemActive($item), $this)) {
$active = $items[$i]['active'] = true;
} else {
$items[$i]['active'] = false;
}
}