I’ve seen a number of people have been trying to build a dynamic submenu that sits underneath the main menu and changes with each main menu.
The standard Yii menu widget assumes or enforces the hard-coding of menu entries within the layout.php file. Within this you can define functions to determine the user context but I felt this would be much better defined within each individual controller. After all, the purpose of the MVC architecture is to divide layout, business logic and data. So this solutions moves that sub-menu logic from the layout.php into each controller.
I based my idea on an article ( here ) on how to use CPortlets to build a static user menu in a sidebar.
So here is the logic to build a widget that is dynamic, such that you can define the sub-menu items in each controller.
components/submenu.php
| 01 | |
| 02 | Yii::import('zii.widgets.CPortlet'); |
| 03 | |
| 04 | class SubMenu extends CPortlet |
| 05 | { |
| 06 | public $title; |
| 07 | public $menu; |
| 08 | |
| 09 | public function init() |
| 10 | { |
| 11 | $this->hideOnEmpty=true; |
| 12 | |
| 13 | $controllerId = Yii::app()->controller; |
| 14 | |
| 15 | if (method_exists($controllerId, 'getSubMenu')) { |
| 16 | $this->menu= $controllerId->getSubMenu(); |
| 17 | } |
| 18 | parent::init(); |
| 19 | } |
| 20 | |
| 21 | protected function renderContent() |
| 22 | { |
| 23 | if (isset ($this->menu)) { |
| 24 | $this->render('subMenu', array('menu'=>$this->menu)); |
| 25 | } |
| 26 | } |
components/views/submenu.php
| 01 | <ul> |
| 02 | <?php |
| 03 | $count = count($menu); |
| 04 | for ($i = 0; $i < $count; $i++) { |
| 05 | $mItem=$menu[$i]; |
| 06 | if (isset($mItem[2])) { |
| 07 | echo "<li ".$mItem[2]." >"; |
| 08 | } else { |
| 09 | echo "<li>"; |
| 10 | } |
| 11 | $mName=$mItem[0]; |
| 12 | $mLink=$mItem[1]; |
| 13 | echo CHtml::link($mName,$mLink)."</li>"; |
| 14 | } |
| 15 | ?> |
| 16 | </ul> |
| 01 | |
| 02 | <?php |
| 03 | $count = count($menu); |
| 04 | for ($i = 0; $i < $count; $i++) { |
| 05 | $mItem=$menu[$i]; |
| 06 | if (isset($mItem[2])) { |
| 07 | echo "<li ".$mItem[2]." >"; |
| 08 | } else { |
| 09 | echo "<li>"; |
| 10 | } |
| 11 | $mName=$mItem[0]; |
| 12 | $mLink=$mItem[1]; |
| 13 | echo CHtml::link($mName,$mLink)."</li>"; |
| 14 | } |
| 15 | ?> |
| 16 | </ul> |
controller/some_controller.php
| 01 | |
| 02 | public function getSubMenu() { |
| 03 | |
| 04 | $subMenuItems=array(); |
| 05 | if(UserModule::isAdmin()) { |
| 06 | $mu=UserModule::t('Manage User'); |
| 07 | $subMenuItems[$mu]='/user/admin'; |
| 08 | $subMenuItems[UserModule::t('List User')]='/user'; |
| 09 | } |
| 10 | $subMenuItems[UserModule::t('Profile')]='/user/profile'; |
| 11 | $subMenuItems[UserModule::t('Edit')]='edit'; |
| 12 | $subMenuItems[UserModule::t('Change password')]='changepassword'; |
| 13 | $subMenuItems[UserModule::t('Logout')]='/user/logout'; |
| 14 | |
| 15 | return $subMenuItems; |
| 16 | |
| 17 | } |
layout/main.php
| 1 | |
| 2 | <div id="submenu"> |
| 3 | <?php $this->widget('SubMenu'); |
| 4 | ?> |
| 5 | </div> |
| 6 | |
You could then add styling like this:
| 1 | |
| 2 | |
| 3 | #submenu ul {padding: 6px 20px 5px 20px; margin: 0px; } |
| 4 | #submenu ul li {display: inline; } |
| 5 | #submenu ul li a { color: #539DC7; background-color: transparent;font-size: 12px; font-weight: bold; text-decoration: none; padding: 5px 8px; border-right: 1px solid #539DC7; } |
| 6 | #submenu ul li a:hover, |
| 7 | #submenu ul li.active a { color: #6399CD; background-color: #EFFDFF; text-decoration: none; } |
see also How to make a dynamic sub-menu – UPDATE
How would this work with CMenu?
Fred
you can use this widget after or independently of your main cMenu widget. See my new post example of using my submenu widget
Thanks
Chris
Very useful
thanks.