我想以编程方式使用MenuItems创建p:menu(它可以工作),每个MenuItem应该有p:contextMenu(它不起作用)。
ManagedBean:
@ManagedBean(name="leftMenuView")
@SessionScoped
public class LeftMenuView {
private MenuModel model;
@PostConstruct
public void init() {
model = new DefaultMenuModel();
DefaultMenuItem item = new DefaultMenuItem("Redirect");
item.setId("redirectMenuItem");
model.addElement(item);
ContextMenu ctxMenu = new ContextMenu();
ctxMenu.setFor("redirectMenuItem");
MenuModel ctxModel = new DefaultMenuModel();
MenuItem ctxItem = new DefaultMenuItem("Remove from favorities");
ctxModel.addElement(ctxItem);
ctxMenu.setModel(ctxModel);
}
(...)
}
视图:
<h:form id="leftForm">
<p:menu id="leftMenu" model="#{leftMenuView.model}" />
</h:form>
出现菜单,但右键单击带有“重定向”标签的MenuItem时,未显示ContextMenu。
我做错了什么?
更新 - 当我添加:
uiComponent = (UIComponent) rootView
.findComponent("leftForm");
uiComponent.getChildren().add(ctxMenu);
它在整个菜单栏上显示上下文菜单。我点击MenuItem或只是菜单组件并不重要。
当我将其更改为:
uiComponent = (UIComponent) rootView
.findComponent(":leftForm:leftMenu:redirectMenuItem");
uiComponent.getChildren().add(ctxMenu);
我得到“java.lang.IllegalArgumentException:leftMenu”
换句话说 - 我希望得到这种行为:
<h:form>
<p:menu id="menu_id">
<p:menuitem id="gmail_id" value="Gmail"/>
<p:menuitem id="hotmail_id" value="Hotmail" />
</p:menu>
<p:contextMenu for="gmail_id">
<p:menuitem value="Save" />
<p:menuitem value="Delete"/>
</p:contextMenu>
</h:form>
但以编程方式(源代码)。
答案 0 :(得分:1)
这是因为当使用DefaultMenuModel
时,有效ID 不您期望它们。它们被覆盖(使用浏览器开发人员工具查看生成的代码时可以看到)。
不使用DefaultMenuModel
,而是使用DynamicMenuModel
。与前者相反,后者允许您设置并保持 ID 您分配。但是你必须在所有内容上设置id,menuitem,子菜单,组等...
可以在每个的实现中看到差异。
答案 1 :(得分:1)
我遇到了同样的问题,这就是我修复它的方法。
我尝试使用DynamicMenuModel
作为@Kukeltje建议,我将自己的自定义ID添加到菜单项中。但是当我为这些ID添加contextmenu
属性时,我一直在
页面中的异常:找不到表达式的组件&#34; leftmenu:sm_leftmenu_KEYSTORE_MANAGEMENT&#34;引自&#34; leftmenu:j_idt240:0:j_idt226&#34;。
所以我又回到DefaultMenuModel
并为每个菜单添加了一个contextMenu,如:
for (AuthTransactions subMenus : subTransactions){
String subMenuName = getI18NString(subMenus.getLabelId(),locale);
DefaultMenuItem item = new DefaultMenuItem(
subMenuName == null ? subMenus.getTransactionCode()
: subMenuName);
item.setCommand("#{" + subMenus.getViewClassName()
+ defaultMethodName + "}");
item.setParam("menuTransactionCode",
subMenus.getTransactionCode());
item.setOnclick("PF('statusDialog').show()");
item.setTitle(subMenus.getTransactionCode());
item.setIcon(subMenus.getIcon());
userMenuModel.addElement(item);
ContextMenu ctxMenu = new ContextMenu();
ctxMenu.setFor("leftmenu:"+subMenus.getTransactionCode());
DynamicMenuModel ctxModel = new DynamicMenuModel();
DefaultMenuItem ctxItem = new DefaultMenuItem("Add/Remove"
+subMenus.getTransactionCode() + " to favorites","ui-icon-star");
ctxItem.setCommand("#{currentUserManager.toggleFavorite}");
ctxItem.setParam("menuTransactionCode", subMenus.getTransactionCode());
ctxItem.setAjax(true);
ctxItem.setOnclick("PF('statusDialog').show()");
ctxItem.setUpdate(":topBar");
ctxModel.addElement(ctxItem);
ctxMenu.setModel(ctxModel);
contextMenuList.add(ctxMenu);
}
但不是使用
<ps:menu id="sm_leftmenu" model="#{userMenuModel}" stateful="false" />
我使用普通的旧HTML和<h:commandLink>
<c:if test="#{userMenuModel != null and userMenuModel.elements !=null and !empty userMenuModel.elements}">
<ul id="leftmenu:sm_leftmenu" class="layout-menubar-container">
<c:forEach var="item" items="#{userMenuModel.elements}">
<li id="#{item.id}" role="menuitem">
<h:commandLink value="#{item.value}" action="#{item.command}" title="#{item.title}" onclick="PF('statusDialog').show();" id="#{item.title}">
<f:param name="menuTransactionCode" value="#{item.title}" />
<i class="#{item.icon} yellow" style="float:left;padding-right:5px;"></i>
</h:commandLink>
</li>
</c:forEach>
</ul>
</c:if>
并添加了下面的conext菜单,如
<h:panelGroup rendered="#{currentUserManager.contextMenuList != null and !empty currentUserManager.contextMenuList}">
<h:dataTable value="#{currentUserManager.contextMenuList}" var="contextMenu">
<h:column>
<p:contextMenu binding="#{contextMenu}" model="#{contextMenu.model}" for="#{contextMenu.for}" styleClass="favCtx"/>
</h:column>
</h:dataTable>
</h:panelGroup>
现在contextMenu将指向<h:commandLink>
,这是一个jsf组件,正如contextMenu的PrimeFaces文档所要求的那样,并且每个菜单项都出现了contextMenu。
和
答案 2 :(得分:0)
您在后端设置的ID在PrimeFaces Class BaseMenuRenderer中再次被覆盖,encodeEnd()带有generateUniqueIds(..)
我为https://github.com/primefaces/primefaces/issues/1039打开了一个问题。
如果你喜欢,就提升它。似乎是PrimeFaces的bug。 它仍然存在于PrimeFaces 5.3.5
中所以答案是,目前无法为MenuItem设置ID。
这是我目前设置ID的解决方法:
将它放在faces-config.xml中以使用您自己的MenuRenderer
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.MenuRenderer</renderer-type>
<renderer-class>de.yourPackage.CustomMenuRenderer</renderer-class>
</renderer>
</render-kit>
然后创建一个像这样的CustomMenuRenderer类,只改变一点不要覆盖IDS:
public class CustomMenuRenderer extends CustomBaseMenuRenderer {
protected void encodeScript(FacesContext context, AbstractMenu abstractMenu) throws IOException {
Menu menu = (Menu) abstractMenu;
String clientId = menu.getClientId(context);
WidgetBuilder wb = getWidgetBuilder(context);
wb.initWithDomReady("PlainMenu", menu.resolveWidgetVar(), clientId)
.attr("toggleable", menu.isToggleable(), false);
if (menu.isOverlay()) {
encodeOverlayConfig(context, menu, wb);
}
wb.finish();
}
protected void encodeMarkup(FacesContext context, AbstractMenu abstractMenu) throws IOException {
ResponseWriter writer = context.getResponseWriter();
Menu menu = (Menu) abstractMenu;
String clientId = menu.getClientId(context);
String style = menu.getStyle();
String styleClass = menu.getStyleClass();
String defaultStyleClass = menu.isOverlay() ? Menu.DYNAMIC_CONTAINER_CLASS : Menu.STATIC_CONTAINER_CLASS;
if (menu.isToggleable()) {
defaultStyleClass = defaultStyleClass + " " + Menu.TOGGLEABLE_MENU_CLASS;
}
styleClass = styleClass == null ? defaultStyleClass : defaultStyleClass + " " + styleClass;
writer.startElement("div", menu);
writer.writeAttribute("id", clientId, "id");
writer.writeAttribute("class", styleClass, "styleClass");
if (style != null) {
writer.writeAttribute("style", style, "style");
}
writer.writeAttribute("role", "menu", null);
encodeKeyboardTarget(context, menu);
if (menu.getElementsCount() > 0) {
writer.startElement("ul", null);
writer.writeAttribute("class", Menu.LIST_CLASS, null);
encodeElements(context, menu, menu.getElements());
writer.endElement("ul");
}
writer.endElement("div");
}
protected void encodeElements(FacesContext context, Menu menu, List<MenuElement> elements) throws IOException {
ResponseWriter writer = context.getResponseWriter();
boolean toggleable = menu.isToggleable();
for (MenuElement element : elements) {
if (element.isRendered()) {
if (element instanceof MenuItem) {
MenuItem menuItem = (MenuItem) element;
String containerStyle = menuItem.getContainerStyle();
String containerStyleClass = menuItem.getContainerStyleClass();
containerStyleClass = (containerStyleClass == null) ? Menu.MENUITEM_CLASS : Menu.MENUITEM_CLASS + " " + containerStyleClass;
if (toggleable) {
UIComponent parent = ((UIComponent) menuItem).getParent();
containerStyleClass = (parent instanceof Submenu) ? containerStyleClass + " " + Menu.SUBMENU_CHILD_CLASS : containerStyleClass;
}
writer.startElement("li", null);
writer.writeAttribute("class", containerStyleClass, null);
writer.writeAttribute("role", "menuitem", null);
if (containerStyle != null) {
writer.writeAttribute("style", containerStyle, null);
}
if (menuItem.getId() != null) {
writer.writeAttribute("id", menuItem.getId(), null);
}
encodeMenuItem(context, menu, menuItem);
writer.endElement("li");
}
else if (element instanceof Submenu) {
encodeSubmenu(context, menu, (Submenu) element);
}
else if (element instanceof Separator) {
encodeSeparator(context, (Separator) element);
}
}
}
}
@SuppressWarnings("unchecked")
protected void encodeSubmenu(FacesContext context, Menu menu, Submenu submenu) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String label = submenu.getLabel();
String icon = submenu.getIcon();
String style = submenu.getStyle();
String styleClass = submenu.getStyleClass();
styleClass = styleClass == null ? Menu.SUBMENU_TITLE_CLASS : Menu.SUBMENU_TITLE_CLASS + " " + styleClass;
boolean toggleable = menu.isToggleable();
//title
writer.startElement("li", null);
if (toggleable) {
writer.writeAttribute("id", submenu.getClientId(), null);
}
writer.writeAttribute("class", styleClass, null);
if (style != null) {
writer.writeAttribute("style", style, null);
}
if (menu.getId() != null) {
writer.writeAttribute("id", menu.getId(), null);
}
writer.startElement("h3", null);
if (menu.isToggleable()) {
encodeIcon(context, label, Menu.EXPANDED_SUBMENU_HEADER_ICON_CLASS);
}
if (icon != null) {
encodeIcon(context, label, "ui-submenu-icon ui-icon " + icon);
}
if (label != null) {
writer.writeText(label, "value");
}
writer.endElement("h3");
writer.endElement("li");
encodeElements(context, menu, submenu.getElements());
}
protected void encodeIcon(FacesContext context, String label, String styleClass) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("span", null);
writer.writeAttribute("class", styleClass, null);
writer.endElement("span");
}
}
最后,您还需要自己的CustomBaseMenuRenderer类:
public class CustomBaseMenuRenderer extends BaseMenuRenderer {
@Override
protected void encodeMenuItem(FacesContext context, AbstractMenu menu, MenuItem menuitem) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String title = menuitem.getTitle();
String style = menuitem.getStyle();
boolean disabled = menuitem.isDisabled();
writer.startElement("a", null);
writer.writeAttribute("tabindex", "-1", null);
if (shouldRenderId(menuitem)) {
writer.writeAttribute("id", menuitem.getClientId(), null);
}
if (title != null) {
writer.writeAttribute("title", title, null);
}
String styleClass = this.getLinkStyleClass(menuitem);
if (disabled) {
styleClass = styleClass + " ui-state-disabled";
}
writer.writeAttribute("class", styleClass, null);
if (style != null) {
writer.writeAttribute("style", style, null);
}
if (disabled) {
writer.writeAttribute("href", "#", null);
writer.writeAttribute("onclick", "return false;", null);
}
else {
setConfirmationScript(context, menuitem);
String onclick = menuitem.getOnclick();
//GET
if (menuitem.getUrl() != null || menuitem.getOutcome() != null) {
String targetURL = getTargetURL(context, (UIOutcomeTarget) menuitem);
writer.writeAttribute("href", targetURL, null);
if (menuitem.getTarget() != null) {
writer.writeAttribute("target", menuitem.getTarget(), null);
}
}
//POST
else {
writer.writeAttribute("href", "#", null);
UIComponent form = ComponentTraversalUtils.closestForm(context, menu);
if (form == null) {
throw new FacesException("MenuItem must be inside a form element");
}
String command;
if (menuitem.isDynamic()) {
String menuClientId = menu.getClientId(context);
Map<String, List<String>> params = menuitem.getParams();
if (params == null) {
params = new LinkedHashMap<String, List<String>>();
}
List<String> idParams = new ArrayList<String>();
idParams.add(menuitem.getId());
params.put(menuClientId + "_menuid", idParams);
command = menuitem.isAjax() ? buildAjaxRequest(context, menu, (AjaxSource) menuitem, form, params) : buildNonAjaxRequest(context, menu, form, menuClientId, params, true);
}
else {
command = menuitem.isAjax() ? buildAjaxRequest(context, (AjaxSource) menuitem, form)
: buildNonAjaxRequest(context, ((UIComponent) menuitem), form, ((UIComponent) menuitem).getClientId(context), true);
}
onclick = (onclick == null) ? command : onclick + ";" + command;
}
if (onclick != null) {
if (menuitem.requiresConfirmation()) {
writer.writeAttribute("data-pfconfirmcommand", onclick, null);
writer.writeAttribute("onclick", menuitem.getConfirmationScript(), "onclick");
}
else {
writer.writeAttribute("onclick", onclick, null);
}
}
}
encodeMenuItemContent(context, menu, menuitem);
writer.endElement("a");
}
@Override
protected boolean shouldRenderId(MenuElement element) {
if (element instanceof UIComponent) {
return shouldWriteId((UIComponent) element);
}
return false;
}
@Override
protected void encodeMarkup(FacesContext context, AbstractMenu abstractMenu) throws IOException {
// TODO Auto-generated method stub
}
@Override
protected void encodeScript(FacesContext context, AbstractMenu abstractMenu) throws IOException {
// TODO Auto-generated method stub
}
}
我现在使用它已经2年了,它就像一个魅力。 但很难过,他们还没有解决它。
答案 3 :(得分:-1)
请看一下页面:
PrimeFaces - 新的MenuModel。
简单示例:
MenuModel model = new DefaultMenuModel();
DefaultSubMenu subMenu = new DefaultSubMenu("some submenu");
DefaultMenuItem menuItem = new DefaultMenuItem("some item");
subMenu.addElement(menuItem);
model.addElement(subMenu);
model.generateUniqueIds();
方法generateUniqueIds()将使您免于自己创建和设置id字符串。