- be created with dynamic structure from backend
- be responsive, i.e. desktop- and mobile-friendly
- have submenu items with navigation links
- support touch events
- support keyboard accessibility
- they are not really responsive
- submenu items only collapse / expand the submenus and can not contain navigation links
- ...
But how to output the dynamic menu structure? ui:repeat is not a choice here because the structure (nested sub menus, etc.) is not known a priori. Fortunately, there is OmniFaces with o:tree, which allows to have full control over the markup of a tree hierarchy by declaring the JSF components or HTML elements in the markup. o:tree does not render any HTML markup by itself. Exactly what I need!
I ended up with this XHTML fragment mixing o:treeNode, o:treeNodeItem, o:treeInsertChildren and HTML elements defined by the mentioned FlexNav menu:
<h:outputScript library="js" name="jquery.flexnav.js"/> <h:outputStylesheet library="css" name="flexnav.css"/> <ul id="mainnavi" class="flexnav" data-breakpoint="640" role="navigation"> <o:tree value="#{mainNavigationBean.treeModel}" var="item"> <o:treeNode level="0"> <o:treeNodeItem> <li class="item"> <a href="#{item.href}" title="#{item.title}">#{item.text}</a> <o:treeInsertChildren/> </li> </o:treeNodeItem> </o:treeNode> <o:treeNode> <ul> <o:treeNodeItem> <li> <a href="#{item.href}" title="#{item.title}">#{item.text}</a> <o:treeInsertChildren/> </li> </o:treeNodeItem> </ul> </o:treeNode> </o:tree> </ul> <h:outputScript id="mainnaviScript" target="body"> $(document).ready(function () { $("#mainnavi").flexNav({'calcItemWidths': true}); }); </h:outputScript>The OmniFaces' TreeModel with menu items is created programmatically. The Java code looks like
public TreeModel<NavigationItemDTO> getTreeModel() { // get menu model from a remote service NavigationContainerDTO rootContainer = remoteService.fetchMainNavigation(...); TreeModel<NavigationItemDTO> treeModel = new ListTreeModel<>(); buildTreeModel(treeModel, rootContainer.getNavItem()); return treeModel; } private void buildTreeModel(TreeModel<NavigationItemDTO> treeModel, List<NavigationItemDTO> items) { for (NavigationItemDTO item : items) { buildTreeModel(treeModel.addChild(item), item.getNavItem()); } }And the end result (desktop variant):
Note that submenus are clickable and can be expanded on mouseover.
You see, JSF is flexible and sometimes you don't need full-blown components. Have fun!
Very helpful, I was looking for something like this
ReplyDeleteThanks Oleg,
(Please post something like this to create autocomplete control with more features than Primefaces control)
Great Post, I love to read articles that are informative and actually have good content. Thank you for sharing your experiences and I look forward to reading more.
ReplyDeleteRyan Levin | Ryan Levin
This is really very informative blog i always visit this blog keep blogging great!!!!!
ReplyDeleteSoftware Development Company in Lucknow
Thanks for sharing the knowledge with us.
ReplyDeleteit's helpful coding for responsive navigation menu. Thanks for sharing informative post.
ReplyDeleteWeb Design Company India | Web Development Company India
its a really informative post
ReplyDeleteThanks for shairng
Ssoftware development company Lucknow