How would I add custom attributes into Zend Framework 2 navigation?
I know I can add id or class -> but that's about it....
1) How would I add data-test='blahblah'
attribute for example?
2) Can I add attribute to li
elements that contain actual links?
$container = new Zend\Navigation\Navigation(array(
array(
'label' => 'Page 1',
'id' => 'home-link',
'uri' => '/',
),
array(
'label' => 'Zend',
'uri' => 'http://www.zend-project.com/',
'order' => 100,
),
);
Edit:
@Bram Gerritsen: Thanks for your answer.
Yes - I can add 'data-test' => 'blahblah'
and retrieve it as $page->get('data-test')
- but this still doesn't append it as an attribute into <a></a>
.... Would I ahve to override htmlify to to that?
The Page classes have some dedicated setters for common attributes (
setLabel
,setId
,setUri
etc), If a setter not exists__set
will be called. See the manual for more information about this and also about extending theAbstractPage
class.Now you can do
$page->get('data_test')
and it will return blahblah.Your second question is about altering the rendering of the menu (adding a attribute to the
li
. ZF2 is using the menu view helper to render a navigation menu. All the navigation view helpers have an option to use your own partial view for rendering usingsetPartial()
.In your viewscript:
In your partial view
menu.phtml
do something like this:This will only render the highest level of the menu. If you have deeper/nested structure your custom view script will end up far more complex.
Hope this helps.
In addition to jmbertucci comment
Problem
exсess caret tag in label which cause problem with:
Splution
To prevent adding tag caret to label you can add support of this parameter at menu config. You should
Go to
protected function renderNormalMenu()
public function htmlify()
Now you can use it:
ps . jmbertucci, you are the Man.
Bram's answer helped point me to a solution, here's what I needed and how I solved it (since I was new to ZF2 and namespaces it took me much longer than it should have, so hopefully this will help others)
Problem
Zend\Navigation
to benefit from itsisActive()
method and the built in translation, ACL, etc support.<li>
element and<a>
element. (ZF2's Menu View Helper supports an 'either or' approach currently)<ul>
elements.<a>
element such asdata-*="..."
Solution Description
Zend\View\Helper\Navigation\Menu
renderNormalMenu()
andhtmlify()
methodsZend\Pages
to add CSS classes and additional attributes to some elementsSolution
Step 1
Created custom View Helper under the Application module
src\Application\View\Helper\NewMenu.php
NewMenu.php
Step 2
Registered new View Helper with the
getViewHelperConfig()
in\module\Application\Module.php
Step 3
In my
layout.phtml
script, I get my Navigation container and pass it to the NewMenu view helper. I also set some options like adding the parent<ul>
class name and not escaping labels so I can add the standard 'dropdown caret' that Bootstrap uses (ie.<b class="caret"></b>
) to a label with a dropdown menu.Intermission
At this point, we should have more or less just duplicated the Menu View Helper. It should produce a navigation the same way the standard View Helper does.
Step 4
In the
NewMenu.php
class, I remove the$addClassToListItem
code to avoid it from placing classes on the wrong element by accident.protected function renderNormalMenu(...)
public function htmlify(...)
Step 5
Add a method to apply CSS class name to
<li>
tags, since we removed the$addClassTolistItem
method. We simply use the Page classes ability to have custom properties and do this:protected function renderNormalMenu
Now, in our Navigation config file, we can simply add a property called
wrapClass
to apply CSS classes to the wrapping element (<li>
).config\autoload\global.php
Step 6
Add the ability to have additional attributes on
<a>
likedata-*
. For Bootstrap 3 you'll needdata-toggle="dropdown"
for example.public function htmlify(...)
In your config file, you can now add a property with an array of additional attributes:
config\autoload\global.php
Step 7
Add the ability to place class names on nested lists container (ie.
<ul>
).protected function renderNormalMenu()
The original code basically said "if this is the first
<ul>
and there's a UL class, add it, else do nothing. So, I added an additional check to say, if a property calledpagesContainerClass
is available, to apply the class to the<ul>
as well.This means we need to add the property on the right Page in our configuration:
config\autoload\global.php
Important to note, the UL class needs to be placed on the first child Page of a child because the conditional statements are wrapped in a the following condition:
After the first child is called, the $dept = $prevDepth and the nested
<ul>
will have already been sent to the string buffer.This solution hasn't been rigorously tested but the idea is that is simply takes the current Menu View Helper, and overloads the two necessary methods and only slightly modifies that.
I've tried to use
setPartial()
but that only helped with the<li>
generation, it was still using the Menu View Helpers'htmlify()
method (all of which was mentioned in Bram's discussion above).So with making those small tweeks to the to methods and using the Page class's ability to have custom properties, I could just add some additional logic to get class names on the
<li>
,<a>
and nested<ul>
classes as well as add additional properties on the<a>
elements, so I could configure myZend\Navigation
from the config to spit out, basically, Bootstrap 3 Navbar markup.The end Layout then just looks like this:
The troubles I kept running into was a better understanding of PHP Namespaces and having needed to include the appropriate Qualified namespaces in my custom View Helper, even though I was extending it.
The other problem, was that the Navigation View Helper can call the Menu View Helper from itself like so:
This won't work:
I'm thinking because of namespace issues with
NewMenu
not being registered in the Navigation View Helper class and I'm not going to extend it just for that.So, hopefully this (long) answer will help others who are struggling with this need.
Cheers!