yii2 icon indicating copy to clipboard operation
yii2 copied to clipboard

Menu parent active status gets broken for the rest of the items when using Closure for one item

Open atrandafir opened this issue 3 years ago • 0 comments

Possibly related to:

  • #15657

What steps will reproduce the problem?

  1. Create a menu with yii\widgets\Menu
  2. Use Closure to determine if one item is active
  3. That item works correctly, including its parent
  4. 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

image

What do you get instead?

  • Only the child item gets activated, but not its parent, when you click the child that doesnt use Closure

image

  • But the child with the Closure works properly

image

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;
  }
}

atrandafir avatar Dec 04 '21 12:12 atrandafir