我在<p:menu>
中有一个<p:dataTable>
,在升级到Mojarra 2.1.22(在GlassFish 3.1.2.2上)时,我们会得到不定期FacesException
:
<p:dataTable id="data"
widgetVar="resultDataTable"
value="#{depotManager.dataModel}"
var="dep"
rowKey="#{dep.id}"
selection="#{depotManager.selectedEntities}"
selectionMode="#{depotManager.singleSelectionMode ? 'single' : 'multiple'}"
...
emptyMessage="#{msg['entity.depot.list.emptyMessage']}">
<p:ajax event="rowSelect"...
<f:facet name="header">
<h:panelGroup id="header"
layout="block">
<p:menu overlay="true"
trigger="sub-client-button"
my="left top"
at="left bottom"
model="#{accountManagerMenuKeeper.subClientMenuModel}" />
我们得到的例外是:
javax.faces.FacesException: Cannot remove the same component twice: content-form:data:menu-item-1
类似的问题在这里:http://forum.primefaces.org/viewtopic.php?f=3&t=23669
我做了一些调查,问题似乎是我们正在使用PrimeFaces 3.5.28的视图范围的bean。我将菜单bean切换到请求范围,如下所述:
http://blog.primefaces.org/?p=2594
我们无法切换到PrimeFaces 4 ......一些例外情况消失了,但不是全部(可能是其中的一半)。所以问题仍然存在。
现在使用唯一ID生成更好地理解问题,阅读https://java.net/jira/browse/JAVASERVERFACES-2283,我可能需要在dataTable命名容器下生成ID。
dataTable的ID是“content-form:data”,所以我想我需要为每个动态菜单项生成唯一的ID,我当前没有这样做(每个客户端一个菜单项,附加简单计数器) ):
for ( Client subClient : subClients )
{
MenuItem item = new MenuItem();
item.setId( "menu-item-" + ( ++i ) );
// item.setId( "content-form:data:menu-item-" + ( ++i ) );
...
}
问:
如何在此处生成正确的ID,例如使用JSF的内置方法,如createUniqueId()等。
对我来说这是一个小问题,因为例外提到了前面有dataTable ID的完整ID:javax.faces.FacesException: Cannot remove the same component twice: content-form:data:menu-item-1
...
答案 0 :(得分:0)
即使在使用简单的请求范围的菜单创建bean的PrimeFaces 3.5.28上,问题也消失了:
@Named
@RequestScoped
public class AccountManagerMenuKeeper implements Serializable
{
private static final long serialVersionUID = 1L;
@Inject
@SeamLogger
protected Logger log;
@Inject
protected SessionHelper sessionHelper;
@Inject
private DepotManager accountManager;
private MenuModel subClientMenuModel;
/**
* @return the subClientMenuModel
*/
public MenuModel getSubClientMenuModel()
{
if ( this.subClientMenuModel == null )
{
buildSubClientMenuModel();
}
return ( this.subClientMenuModel );
}
/**
* Builds the menu model for adding sub-clients.
*
*/
private void buildSubClientMenuModel()
{
this.subClientMenuModel = new DefaultMenuModel();
List<Client> subClients = this.accountManager.getWritableSubClients();
if ( subClients == null || subClients.isEmpty() )
return;
// Necessary instances
FacesContext facesContext = FacesContext.getCurrentInstance();
ELContext elContext = facesContext.getELContext();
Application application = facesContext.getApplication();
ExpressionFactory factory = application.getExpressionFactory();
int i = 0;
for ( Client subClient : subClients )
{
MenuItem item = new MenuItem();
item.setId( "menu-item-" + ( ++i ) );
item.setValue( subClient.getName() );
item.setProcess( "@this" );
item.setUpdate( ":content-form" );
item.setDisabled( this.accountManager.isReadOnly() || !this.accountManager.isSingleSelectionMode() || EMode.ADD.equals( this.accountManager.getMode() ) || EMode.EDIT.equals( this.accountManager.getMode() ) );
item.setActionExpression( factory.createMethodExpression( elContext, "#{depotManager.add}", String.class, new Class[] {} ) );
ValueExpression targetExpression = factory.createValueExpression( elContext, "#{depotManager.selectedSubClientId}", Long.class );
ValueExpression valueExpression = factory.createValueExpression( elContext, "" + subClient.getId(), Long.class );
item.addActionListener( new SwitchableSetPropertyActionListener( targetExpression, valueExpression ) );
this.subClientMenuModel.addMenuItem( item );
}
}
}
这将/应该适用于较新的Mojarra版本。 (DUH)