Я пытался задать более конкретный вопрос, но я думаю, что, возможно, я был слишком конкретным, поэтому я уменьшу масштаб, чтобы получить лучший совет.
Я пытаюсь создать составной / пользовательский компонент, который будет принимать два атрибута
- Список строк -> имена полей
- список списков
<String, Value>
-> групп полей с <fieldName, fieldValue>
пример значения:
[Street, Country, State, ZipCode]
[{(Street, Greenfield), (Country, USA)}, {(Country, Canada), (ZipCode, 3333)}]
Компонент отобразит это, основываясь на атрибутах:
Причина, по которой у меня возникают трудности с этим компонентом, заключается в том, что я не знаю, как правильно поддерживать заполнители для полей, которые не были введены изначально, но могут быть добавлены пользователем через компонент.
В приведенном выше примере для первого набора это будут 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;
}
}