Jsf 每次使用时都在复合组件中获取相同的“componentType”实例

Jsf 每次使用时都在复合组件中获取相同的“componentType”实例,jsf,jsf-2,myfaces,composite-component,Jsf,Jsf 2,Myfaces,Composite Component,大家好,这是一个Wierd问题,我正在使用一个我编写的复合组件,我从先前使用CC的backingbean(componentTypebean)获得的值 我不知道如何更好地描述这一点,而不仅仅是显示代码。 我将尽量简短地介绍一下,并删去多余的部分: 这是复合组件的定义: <cc:interface componentType="dynamicFieldGroupList"> <cc:attribute name="coupletClass" /> <cc:

大家好,这是一个Wierd问题,我正在使用一个我编写的
复合组件
,我从先前使用CC的backingbean(componentTypebean)获得的值

我不知道如何更好地描述这一点,而不仅仅是显示代码。 我将尽量简短地介绍一下,并删去多余的部分: 这是复合组件的定义:

<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");
    }

}
@FacesComponent(value=“dynamicFieldGroupList”)
//要在componentType属性中指定。
@SuppressWarnings({“rawtypes”,“unchecked”})
//无论如何,我们不关心实际的模型项类型。
公共类DynamicFieldGroupList扩展了UIComponentBase实现
NamingContainer
{
私有瞬态数据模型;
@凌驾
公共字符串getFamily()
{
返回“javax.faces.NamingContainer”;//重要!对于
//复合组件。
}
公共数据模型getModel()
{
if(model==null)
{
model=新的ListDataModel(getList());
}
收益模型;
}
私有列表getList()
{//不要将此方法公开!否则将在无限循环中结束
//每次都叫自己。
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
Internal#control_component
组件中的控件输出显示以前使用的值

值第一次是正确的


我猜这是使用CC bean时的一个基本错误,否则它可能是MyFaces2.1(我正在使用)中的一个bug。

这里描述的问题是JSF中一个已知的isse,它被复合组件的使用所隐藏。这是如此重要和困难,因此我在博客中为这一条创建了一个详细的答案:

为了简短地回答这个问题,我要告诉你,它不是MyFaces2.1中的bug。请使用2.1.1,因为这是2.1.0的快速错误修复版本。在JSF2.1中,h:dataTable有一个名为rowStatePreserved的新属性,这个场景只是“这个小宝贝”变得有用的一个例子。只需将ui:repeat替换为h:dataTable并添加rowStatePreserved=“true”。那就行了。如果需要操作模型(添加或删除行),可以使用tomahawk t:dataTable和t:dataList,但现在必须创建快照版本。注意,这是目前在任何不同的JSF框架中都没有的新东西(2011年6月)


如果您需要更多信息,请随时与专家联系。

对这种行为的解释很简单:视图中只定义了一个组件。因此,只有一个支持组件和一个模型。由于模型是在首次获取时延迟加载的,因此在父迭代组件的每次迭代中都会重用相同的模型

不会在视图构建期间运行(与JSTL一样),而是在视图渲染期间运行。因此,视图中的组件在物理上不如通过
迭代的项目多。如果您使用的是
(或在视图构建期间运行的任何其他迭代标记),那么复合组件的行为将与您预期的一样

您希望更改数据模型在备份组件中的保存方式。您希望为父迭代组件的每次迭代保留一个单独的数据模型。其中一种方法是替换
model
属性,如下所示:

private Map<String, DataModel> models = new HashMap<String, DataModel>();

public DataModel getModel() {
    DataModel model = models.get(getClientId());
    if (model == null) {
        model = models.put(getClientId(), new ListDataModel(getList()));
    }
    return model;
}
private Map models=new HashMap();
公共数据模型getModel(){
DataModel=models.get(getClientId());
if(model==null){
model=models.put(getClientId(),newlistdatamodel(getList());
}
收益模型;
}
另见:

谢谢。我尝试升级到2.1.1并使用
h:datatable
,但没有成功。我不能真正使用tomahawk。好吧,我没有注意“model”变量的使用。在JSF2.1中,现在存在一个名为TransientStateHelper的接口,它有两种方法:getTransient和PuttTransient。使用该映射,从JSF规范的角度来看,rowStatePreserved=“true”是首选,但请注意,MyFaces中UIData的impl使用了类似的方法,即使用getClientId()。从外部包装列表是可疑的,因为存在与dataTable相关的规则(如果不存在验证错误,请在encodeBegin之前重新蚀刻模型)。在我看来,使用#{cc.list}代替#{cc.model}更好。谢谢,非常有趣。我不知道如何使用这个新界面。有没有示例代码可以作为参考?(或者一些好的文档?)JSF2.1相对较新。Mojarra的第一个版本于3月发布,5月在MyFaces上发布。我不知道有哪篇文章讨论过这一点,但您可以查看并单击JSF2.1文档,看看有什么新内容。简言之,该接口允许您使用类似于映射的约定,因此您可以在组件内部调用getTransientStateHelper().PuttTransient(…),避免使用瞬态变量,并允许使用实际的每行组件状态。一个例子是UIForm submitted属性。对于您的问题,请尝试不要将模型存储在CCM上谢谢!!为了理解视图构建/渲染时间主题,我肯定会阅读更多内容。有什么特别的文章可以推荐吗?不客气。对不起,我没有想到具体的文章。为了更好地从上到下理解JSF,我只能推荐《JSF2.0:完整参考》一书。对此我感到抱歉,但我太快了,没有把它作为答案。在实现您的解决方案后,我仍然会遇到这个错误。我现在正在调查此事。。如果我找到,我会提供更多细节。