1

我试着问一个more specific的问题,但我认为我可能过于具体,所以我会缩小以获得更好的建议。 我试图创建一个复合/自定义组件,将接受两个属性如何使用自定义/复合组件执行此操作?

  1. 字符串列表 - >团场与<fieldName, fieldValue> - >字段名
  2. 一个<String, Value>的名单列表

示例值:

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

该组件将呈现此基础上,属性:

enter image description here

我有这个成分困难的原因是,我不知道什么是保持占位符的正确方法做用于最初没有输入但可以由用户通过组件添加的字段。

在上例中,对于第一组,这些将是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> 

组件豆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; 
    } 

} 

回答

2

您可以使用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> 
+2

我爱你怎么来了一个解决方案,使我的代码大部分冗余:-) – Ben

+0

不客气:) – BalusC