PrimeFaces 动态菜单:不能删除同一个组件两次和 ID 生成
PrimeFaces dynamic menu: Cannot remove the same component twice and ID generation
我在 <p:dataTable>
中有一个 <p:menu>
,在升级到 Mojarra 2.1.22(在 GlassFish 3.1.2.2 上)时,我们变得不规则 FacesException
s:
<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() 等?
我有点奇怪,因为异常提到前面有数据表ID的完整ID:javax.faces.FacesException: Cannot remove the same component twice: content-form:data:menu-item-1
...
即使在 PrimeFaces 3.5.28 上使用简单的请求范围的菜单创建 bean,问题也消失了:
@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 );
}
}
}
此 will/should 适用于较新的 Mojarra 版本。 (呃)
我在 <p:dataTable>
中有一个 <p:menu>
,在升级到 Mojarra 2.1.22(在 GlassFish 3.1.2.2 上)时,我们变得不规则 FacesException
s:
<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() 等?
我有点奇怪,因为异常提到前面有数据表ID的完整ID:javax.faces.FacesException: Cannot remove the same component twice: content-form:data:menu-item-1
...
即使在 PrimeFaces 3.5.28 上使用简单的请求范围的菜单创建 bean,问题也消失了:
@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 );
}
}
}
此 will/should 适用于较新的 Mojarra 版本。 (呃)