PrimeFaces menuItem中#{component}指向错误问题求助
问题背景
在JSF 2.2 + PrimeFaces 13.0.5环境下,实现菜单选中样式时,原写法需要手动传入viewId到styleClass的EL表达式中:
<p:menuitem value="My menu item" outcome="/some-view-id" styleClass="#{currentView.isView('some-view-id') ? 'selected':''}" />
尝试通过#{component.outcome}自动获取当前菜单项的outcome以实现通用逻辑时,发现#{component}指向的是父组件<p:menu>而非当前<p:menuitem>,导致逻辑失效。使用binding属性虽可行,但需为每个菜单项单独声明绑定,无法达到通用目的。已知该问题在PrimeFaces 13.0.6中已修复,以下是当前版本的可行解决办法:
解决办法
办法一:在托管Bean中添加通用判断方法
在你的currentView托管Bean中新增一个无需传入参数的方法,通过JSF上下文获取当前正在渲染的菜单项组件,自动提取其outcome并判断是否为当前视图:
import javax.faces.context.FacesContext; import javax.faces.component.UIComponent; import org.primefaces.component.menuitem.MenuItem; public boolean isCurrentMenuItemSelected() { FacesContext context = FacesContext.getCurrentInstance(); UIComponent currentComponent = UIComponent.getCurrentComponent(context); // 确认当前组件是PrimeFaces菜单项 if (currentComponent instanceof MenuItem) { MenuItem menuItem = (MenuItem) currentComponent; String outcome = menuItem.getOutcome(); // 复用原有判断当前视图的逻辑 return isView(outcome); } return false; }
页面中直接调用该方法即可:
<p:menuitem value="My menu item" outcome="/some-view-id" styleClass="#{currentView.currentMenuItemSelected ? 'selected':''}" />
办法二:封装复合组件复用逻辑
创建一个Facelets复合组件,将菜单项的选中样式逻辑封装在内,避免重复代码:
- 在
WEB-INF/tags目录下创建menuItem.taglib.xml(若目录不存在则新建),内容如下:
<?xml version="1.0" encoding="UTF-8"?> <facelet-taglib xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd" version="2.2"> <namespace>http://example.com/jsf/custom</namespace> <tag> <tag-name>menuItem</tag-name> <source>/WEB-INF/components/menuItem.xhtml</source> </tag> </facelet-taglib>
- 在
WEB-INF/components目录下创建menuItem.xhtml复合组件文件:
<ui:component xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:p="http://primefaces.org/ui"> <p:menuitem value="#{cc.attrs.value}" outcome="#{cc.attrs.outcome}" styleClass="#{currentView.isView(cc.attrs.outcome) ? 'selected':''}" /> </ui:component>
- 在页面中引入自定义命名空间并使用复合组件:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui" xmlns:my="http://example.com/jsf/custom"> <!-- 使用自定义菜单项组件 --> <my:menuItem value="My menu item" outcome="/some-view-id" /> </html>
办法三:直接升级PrimeFaces版本
若项目允许,直接升级到PrimeFaces 13.0.6及以上版本,该版本已修复#{component}指向错误的问题,可直接使用最初设想的通用写法:
<p:menuitem value="My menu item" outcome="/some-view-id" styleClass="#{currentView.isView(component.outcome) ? 'selected':''}" />
内容的提问来源于stack exchange,提问作者Nikola
相关产品推荐
相关产品推荐

