Как я могу сделать это с пользовательским / составным компонентом? - PullRequest
1 голос
/ 23 июня 2011

Я пытался задать более конкретный вопрос, но я думаю, что, возможно, я был слишком конкретным, поэтому я уменьшу масштаб, чтобы получить лучший совет. Я пытаюсь создать составной / пользовательский компонент, который будет принимать два атрибута

  1. Список строк -> имена полей
  2. список списков <String, Value> -> групп полей с <fieldName, fieldValue>

пример значения:

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

Компонент отобразит это, основываясь на атрибутах:

enter image description here

Причина, по которой у меня возникают трудности с этим компонентом, заключается в том, что я не знаю, как правильно поддерживать заполнители для полей, которые не были введены изначально, но могут быть добавлены пользователем через компонент.

В приведенном выше примере для первого набора это будут State и ZipCode.

Моя идея состояла в том, чтобы создать фиктивный объект со всеми полями и при отправке скопировать значения фиктивного объекта в структуру данных, переданную в атрибутах. Проблема, с которой я столкнулся, заключалась в том, что я не знал, как читать значения при создании компонента, и как изменять список, передаваемый через атрибут при отправке.

Я скоро добавлю пример кода (хотя это не должно быть решающим для ответа на этот вопрос)

Спасибо, что прочитали это далеко !! : -)

Мой код (Опять же, не требуется для ответа на вопрос, но может быть полезно для понимания моего вызова)

Код составного компонента:

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

Java-код компонента EJB:

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

}

1 Ответ

2 голосов
/ 23 июня 2011

Вы можете использовать Map для хранения значений для каждой группы.

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

Предполагая, что у вас есть все эти карты в List<Map<String, Object>> и имена полей в List<String>,тогда вы можете получить / установить их все в основном следующим образом

<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>
...