我试图问一个更具体的问题,但我认为我可能过于具体,所以我会缩小以获得更好的建议。我正在尝试创建一个将接受两个属性的复合/自定义组件
- 字符串列表 --> 字段名称
<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>
组件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;
}
}