每次使用时在复合组件中获取相同的`componentType`实例 [英] Getting same instance of `componentType` in composite component on every use

查看:103
本文介绍了每次使用时在复合组件中获取相同的`componentType`实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个奇怪的问题,即我正在使用自己编写的Composite Component,并且从以前使用CC的后备bean(componentType bean)中获取了值

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)

除了展示代码之外,我不知道如何更好地描述这一点. 我将简要介绍一下,并裁掉多余的部分: 这是Composite Component定义:

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>

CC bean定义:

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

}

以及使用代码:

<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组件内部的控件输出显示以前使用的值.

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.

第一次值正确...

我想这是使用CC Bean的根本性错误,否则可能是MyFaces 2.1(我正在使用的错误)

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)

推荐答案

对此行为的解释很简单:视图中仅定义了一个组件.因此,只有一个模型具有一个后备组件.由于该模型是在初次获取时被延迟加载的,因此同一模型会在父迭代组件的每次迭代中重用.

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.

<ui:repeat>不在视图构建期间运行(如JSTL一样),而是在视图呈现期间运行.因此,视图中的组件实际上不如<ui:repeat>迭代的项那么多.如果您使用的是<c:forEach>(或在视图构建期间运行的任何其他迭代标签),则复合组件的行为将符合您的预期.

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.

您想更改数据模型在后备组件中的保存方式.您想为父迭代组件的每次迭代保留一个单独的数据模型.一种方法是如下替换model属性:

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:

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

另请参见:

  • 什么是视图构建时间?
  • See also:

    • What's the view build time?
    • 这篇关于每次使用时在复合组件中获取相同的`componentType`实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆