如何使用自定义/复合组件来做到这一点?

发布于 2024-11-16 22:01:08 字数 5403 浏览 7 评论 0 原文

我试图问一个更具体的问题但我认为我可能过于具体,所以我会缩小范围以获得更好的建议。 我正在尝试创建一个复合/自定义组件,它将接受两个属性

  1. 字符串列表 -->字段名称
  2. 列表的列表 -->具有

示例值的字段组:

  1. [Street, Country, State, ZipCode]
  2. [{(Street, Greenfield), (Country, USA)}, {(Country, Canada), (ZipCode, 3333)}]

该组件将根据以下属性呈现此内容:

在此处输入图像描述

我在使用此组件时遇到困难的原因是我不知道维护占位符的正确方法是什么最初未输入但可以由用户通过组件添加的字段。

在上面的示例中,对于第一组,这些将是 StateZipCode

我的想法是创建一个包含所有字段的虚拟对象,并在提交时将虚拟对象的值复制到属性中传递的数据结构。 我面临的问题是不知道如何读取组件创建时的值以及如何更改提交时通过属性传递的列表。

我将很快添加示例代码(尽管这不应该是回答这个问题的关键)

感谢您阅读到目前为止! :-)

我的代码(同样,不需要回答问题,但可能有助于理解我的挑战)

复合组件代码:

<cc:interface componentType="dynamicFieldList">
    <cc:attribute name="styleClass" default="fieldType" />
    <cc:attribute name="form" default="@form"
        shortDescription="If used, this is the name of the form that will get executed" />
    <cc:attribute name="list" type="java.util.List" required="true"
        shortDescription="The values of the list. The type must be List of FieldGroup" />
    <cc:attribute name="groupTypes" type="java.util.List" required="true"
        shortDescription="The types that will be available to choose from for each field. The type of this must be List of FieldType" />
</cc:interface>

<cc:implementation>
    <h:dataTable id="table" value="#{cc.model}" var="fieldGroup">
        <h:column>
            <ui:repeat var="field" value="#{fieldGroup.values}">
                <utils:fieldType value="#{field.value}" type="#{field.type}"/>
            </ui:repeat>
        </h:column>
        <h:column>
            <h:commandButton value="delete" action="#{cc.remove}">
                <f:ajax render="#{cc.attrs.form}" execute="#{cc.attrs.form}" />
            </h:commandButton>
        </h:column>
    </h:dataTable>
    <h:commandButton value="add" action="#{cc.add}">
        <f:ajax render="#{cc.attrs.form}" execute="#{cc.attrs.form}" />
    </h:commandButton>
</cc:implementation>

组件 bean java 代码:

@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;
    private List<FieldGroup> displayList;

    public DynamicFieldGroupList()
    {
        super();
        List<FieldGroup> list = new ArrayList<FieldGroup>();

        for (FieldGroup group : getList()){
            FieldGroup currGroup = new FieldGroup("Untitled");

            //Assumption - Each type may exist only once in a group.
            Map<FieldType, FieldDetail> hash = new HashMap<FieldType, FieldDetail>();

            for (FieldDetail detail: group.getDetails()){
                hash.put(detail.getType(), detail); 
            }

            // While creating the dummy object, insert values the exist or placeholders if they don't.
            for (FieldType type : getGroupTypes()){
                if (hash.containsKey(type)){
                    currGroup.addDetail(hash.get(type));
                } else {
                    currGroup.addDetail(new FieldDetail(type,null));
                }
            }

            list.add(currGroup);
        }

        // Assign the created list to be the displayed (dummy) object
        setDisplayList(list);
    }

    public void add()
    {
        // Add a new group of placeholders
        FieldGroup group = new FieldGroup("Untitled");

        for (FieldType type: getGroupTypes()){
            group.addDetail(new FieldDetail(type, null));
        }

        getList().add(group);
    }

    public void remove()
    {
        getDisplayList().remove(model.getRowData());
    }

    @Override
    public String getFamily()
    {
        return "javax.faces.NamingContainer"; // Important! Required for
                                                // composite components.
    }

    public DataModel getModel()
    {
        if (model == null)
            model = new ListDataModel(getDisplayList());
        return model;
    }

    private List<FieldGroup> getList()
    { // Don't make this method public! Ends otherwise in an infinite loop
        // calling itself everytime.
        return (List) getAttributes().get("list");
    }

    private List<FieldType> getGroupTypes()
    { // Don't make this method public! Ends otherwise in an infinite loop
        // calling itself everytime.
        return (List) getAttributes().get("groupTypes");
    }

    public void setDisplayList(List<FieldGroup> displayList)
    {
        this.displayList = displayList;
    }

    public List<FieldGroup> getDisplayList()
    {
        return displayList;
    }

}

I tried to ask a more specific question but I think i may have been overly specific so I'll zoom out to get a better advice.
I'm trying to create a composite/custom component that will accept two attributes

  1. A list of strings --> names of fields
  2. a list of lists of <String, Value> --> groups of fields with <fieldName, fieldValue>

example values:

  1. [Street, Country, State, ZipCode]
  2. [{(Street, Greenfield), (Country, USA)}, {(Country, Canada), (ZipCode, 3333)}]

The component will render this, based on the attributes:

enter image description here

The reason I am having difficulties with this component is that I don't know what's the proper way to maintain placeholders for fields that were not entered originally but can be added by the user through the component.

In the above example, for the first set, these would be State and ZipCode.

My Idea was to create a dummy object with all the fields and on submittion copy the dummy object's values to the data structure passed in the attributes.
The problem I was facing was not knowing how to read the values on component creation and altering the List passed through the attribute on submission.

I will add sample code soon (Although that shouldn't be a crucial for answering this question)

Thank you just for reading this far!! :-)

My Code (Again, not required for answering the question but may be helpful to understand my challenge)

The Composite Component Code:

<cc:interface componentType="dynamicFieldList">
    <cc:attribute name="styleClass" default="fieldType" />
    <cc:attribute name="form" default="@form"
        shortDescription="If used, this is the name of the form that will get executed" />
    <cc:attribute name="list" type="java.util.List" required="true"
        shortDescription="The values of the list. The type must be List of FieldGroup" />
    <cc:attribute name="groupTypes" type="java.util.List" required="true"
        shortDescription="The types that will be available to choose from for each field. The type of this must be List of FieldType" />
</cc:interface>

<cc:implementation>
    <h:dataTable id="table" value="#{cc.model}" var="fieldGroup">
        <h:column>
            <ui:repeat var="field" value="#{fieldGroup.values}">
                <utils:fieldType value="#{field.value}" type="#{field.type}"/>
            </ui:repeat>
        </h:column>
        <h:column>
            <h:commandButton value="delete" action="#{cc.remove}">
                <f:ajax render="#{cc.attrs.form}" execute="#{cc.attrs.form}" />
            </h:commandButton>
        </h:column>
    </h:dataTable>
    <h:commandButton value="add" action="#{cc.add}">
        <f:ajax render="#{cc.attrs.form}" execute="#{cc.attrs.form}" />
    </h:commandButton>
</cc:implementation>

The component bean java code:

@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;
    private List<FieldGroup> displayList;

    public DynamicFieldGroupList()
    {
        super();
        List<FieldGroup> list = new ArrayList<FieldGroup>();

        for (FieldGroup group : getList()){
            FieldGroup currGroup = new FieldGroup("Untitled");

            //Assumption - Each type may exist only once in a group.
            Map<FieldType, FieldDetail> hash = new HashMap<FieldType, FieldDetail>();

            for (FieldDetail detail: group.getDetails()){
                hash.put(detail.getType(), detail); 
            }

            // While creating the dummy object, insert values the exist or placeholders if they don't.
            for (FieldType type : getGroupTypes()){
                if (hash.containsKey(type)){
                    currGroup.addDetail(hash.get(type));
                } else {
                    currGroup.addDetail(new FieldDetail(type,null));
                }
            }

            list.add(currGroup);
        }

        // Assign the created list to be the displayed (dummy) object
        setDisplayList(list);
    }

    public void add()
    {
        // Add a new group of placeholders
        FieldGroup group = new FieldGroup("Untitled");

        for (FieldType type: getGroupTypes()){
            group.addDetail(new FieldDetail(type, null));
        }

        getList().add(group);
    }

    public void remove()
    {
        getDisplayList().remove(model.getRowData());
    }

    @Override
    public String getFamily()
    {
        return "javax.faces.NamingContainer"; // Important! Required for
                                                // composite components.
    }

    public DataModel getModel()
    {
        if (model == null)
            model = new ListDataModel(getDisplayList());
        return model;
    }

    private List<FieldGroup> getList()
    { // Don't make this method public! Ends otherwise in an infinite loop
        // calling itself everytime.
        return (List) getAttributes().get("list");
    }

    private List<FieldType> getGroupTypes()
    { // Don't make this method public! Ends otherwise in an infinite loop
        // calling itself everytime.
        return (List) getAttributes().get("groupTypes");
    }

    public void setDisplayList(List<FieldGroup> displayList)
    {
        this.displayList = displayList;
    }

    public List<FieldGroup> getDisplayList()
    {
        return displayList;
    }

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

娇俏 2024-11-23 22:01:08

您可以使用 Map 来保存每个组的值。

Map<String, Object> values = new HashMap<String, Object>();

假设您将所有这些映射都放在 List> 中,并将字段名称放在 List 中,那么您可以获取/基本上全部设置如下

<ui:repeat value="#{allValues}" var="values">
    <ui:repeat value="#{fieldNames}" var="fieldName">
        <h:outputLabel value="#{fieldName}" />
        <h:inputText value="#{values[fieldName]}" />
        <br/>
    </ui:repeat>
</ui:repeat>

You can use a Map to hold the values for each group.

Map<String, Object> values = new HashMap<String, Object>();

Assuming that you've all those maps in a List<Map<String, Object>> and the field names in a List<String>, then you can get/set them all basically as follows

<ui:repeat value="#{allValues}" var="values">
    <ui:repeat value="#{fieldNames}" var="fieldName">
        <h:outputLabel value="#{fieldName}" />
        <h:inputText value="#{values[fieldName]}" />
        <br/>
    </ui:repeat>
</ui:repeat>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文