每次使用时在复合组件中获取相同的“componentType”实例
您好,有一个奇怪的问题,其中我使用了我编写的Composite Component
,并且我从之前使用 CC 的支持 bean(componentType
bean)中获取了值
除了展示代码之外,我不知道如何更好地描述这一点。 我会尽量简短地介绍一下并删除多余的部分: 这是 Composite Component
定义:
<cc:interface componentType="dynamicFieldGroupList">
<cc:attribute name="coupletClass" />
<cc:attribute name="form" default="@form"/>
<cc:attribute name="list" type="java.util.List" required="true"/>
<cc:attribute name="fieldNames" type="java.util.List" required="true" />
</cc:interface>
<cc:implementation>
<h:dataTable value="#{cc.model}" var="currLine">
<h:column>
<h:outputText id="inner_control_component" value="Inner Look at currLine:#{currLine}"/>
</h:column>
</h:dataTable>
</cc:implementation>
CC bean 定义:
@FacesComponent(value = "dynamicFieldGroupList")
// To be specified in componentType attribute.
@SuppressWarnings({ "rawtypes", "unchecked" })
// We don't care about the actual model item type anyway.
public class DynamicFieldGroupList extends UIComponentBase implements
NamingContainer
{
private transient DataModel model;
@Override
public String getFamily()
{
return "javax.faces.NamingContainer"; // Important! Required for
// composite components.
}
public DataModel getModel()
{
if (model == null)
{
model = new ListDataModel(getList());
}
return model;
}
private List<Map<String, String>> getList()
{ // Don't make this method public! Ends otherwise in an infinite loop
// calling itself everytime.
return (List) getAttributes().get("list");
}
}
以及使用代码:
<ui:repeat var="group" value="#{currentContact.detailGroups}">
<h:panelGroup rendered="#{not empty group.values}">
<h:outputText id="controlMsg" value=" list:#{group.values}" /><br/><br/>
<utils:fieldTypeGroupList list="#{group.values}"
fieldNames="#{group.fields}" coupletClass="utils" />
</h:panelGroup>
</ui:repeat>
id controlMsg
的文本在 #{group.values} 中显示正确的值
而 id inner_control_component
组件内的控制输出则显示之前使用的值。
这些值第一次是正确的...
我猜这是使用 CC bean 时的基本错误,否则可能是 MyFaces 2.1
(我正在使用的)的错误
Hi Have this Wierd Issue in which I am using a Composite Component
which I wrote and I get values from the previous use of the backing bean of the CC (the componentType
bean)
I don't know how to describe this better than just show the code.
I'll try to be brief about it and cut the redundant parts:
This is the Composite Component
definition:
<cc:interface componentType="dynamicFieldGroupList">
<cc:attribute name="coupletClass" />
<cc:attribute name="form" default="@form"/>
<cc:attribute name="list" type="java.util.List" required="true"/>
<cc:attribute name="fieldNames" type="java.util.List" required="true" />
</cc:interface>
<cc:implementation>
<h:dataTable value="#{cc.model}" var="currLine">
<h:column>
<h:outputText id="inner_control_component" value="Inner Look at currLine:#{currLine}"/>
</h:column>
</h:dataTable>
</cc:implementation>
The CC bean defintion:
@FacesComponent(value = "dynamicFieldGroupList")
// To be specified in componentType attribute.
@SuppressWarnings({ "rawtypes", "unchecked" })
// We don't care about the actual model item type anyway.
public class DynamicFieldGroupList extends UIComponentBase implements
NamingContainer
{
private transient DataModel model;
@Override
public String getFamily()
{
return "javax.faces.NamingContainer"; // Important! Required for
// composite components.
}
public DataModel getModel()
{
if (model == null)
{
model = new ListDataModel(getList());
}
return model;
}
private List<Map<String, String>> getList()
{ // Don't make this method public! Ends otherwise in an infinite loop
// calling itself everytime.
return (List) getAttributes().get("list");
}
}
And the use code:
<ui:repeat var="group" value="#{currentContact.detailGroups}">
<h:panelGroup rendered="#{not empty group.values}">
<h:outputText id="controlMsg" value=" list:#{group.values}" /><br/><br/>
<utils:fieldTypeGroupList list="#{group.values}"
fieldNames="#{group.fields}" coupletClass="utils" />
</h:panelGroup>
</ui:repeat>
The text of id controlMsg
displays the correct values in #{group.values}
while the control output inside the component of id inner_control_component
shows the values from the previous use.
The values are correct the first time...
I guess it's a fundemental error in use of a CC bean, otherwise it could be a bug with MyFaces 2.1
(Which I'm using)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这种行为的解释很简单:视图中只定义了一个组件。因此,一种模型也只有一个支持组件。由于模型是在第一次获取时延迟加载的,因此在父迭代组件的每次迭代中都会重用相同的模型。
不在视图构建期间运行(如 JSTL 那样),而是在视图渲染期间运行。因此,视图中的组件实际上没有
迭代的项目那么多。如果您使用
(或在视图构建期间运行的任何其他迭代标记),则复合组件的行为将符合您的预期。您希望更改数据模型在支持组件中的保存方式。您希望为父迭代组件的每次迭代保留一个单独的数据模型。其中一种方法是替换
model
属性,如下所示:另请参阅:
The explanation for this behaviour is simple: there's only one component definied in the view. So there's also only one backing component with one model. Since the model is lazily loaded on first get, the same model is been reused in every iteration of a parent iterating component.
The
<ui:repeat>
doesn't run during view build time (as JSTL does), but during view render time. So there are physically not as many components in the view as items which are iterated by<ui:repeat>
. If you were using<c:forEach>
(or any other iteration tag which runs during view build time), then the composite component would have behaved as you'd expect.You would like to change the way how the datamodel is kept in the backing component. You would like to preserve a separate datamodel for each iteration of a parent iterating component. One of the ways is to replace the
model
property as follows:See also:
这里描述的问题是 JSF 中一个已知的老问题,被复合组件的使用所隐藏。它是如此重要且如此困难,因此我在博客条目中为此创建了一个详细答案:数据表每行的 JSF 组件状态
为了使这个答案简短,我会告诉你这不是 MyFaces 2.1 中的错误。请使用 2.1.1,因为这是 2.1.0 的快速错误修复版本。在 JSF 2.1 中,h:dataTable 有一个名为 rowStatePreserved 的新属性,这种情况只是“这个小宝贝”变得有用的一种情况。只需将 ui:repeat 替换为 h:dataTable 并添加 rowStatePreserved="true" 即可。这样就可以了。如果您需要操作模型(添加或删除行),您可以使用 tomahawk t:dataTable 和 t:dataList,但您现在必须使用快照版本。请注意,这是目前任何其他 JSF 框架中都不可用的新内容(2011 年 6 月)。
如果您需要更多信息,请随时关注 Twitter 上的 MyFaces 团队 或向 MyFaces 用户和开发人员邮件列表。
The problem described here is an old known isse in JSF, hidden by the usage of composite components. It is so important and so difficult, that instead answer here I create a detailed answer in a blog entry for this one: JSF component state per row for datatables
To keep this answer short, I'll say to you it is not a bug in MyFaces 2.1. Please use 2.1.1, because that is a quick bug fix version of 2.1.0. In JSF 2.1 there is a new property for h:dataTable called rowStatePreserved, and this scenario is just one case where "this little baby" becomes useful. Just replace ui:repeat with h:dataTable and add rowStatePreserved="true". That will do the trick. If you need to manipulate the model (add or remove rows) you can use tomahawk t:dataTable and t:dataList, but you will have to take an snapshot version for now. Note this is new stuff not available in any different JSF framework an the moment (JUN 2011).
If you need more info, keep tuned with MyFaces Team on Twitter or ask to the experts on MyFaces Users and Dev Mailing Lists.