如何使用自定义/复合组件执行此操作?

时间:2011-06-23 06:42:41

标签: jsf jsf-2 dynamic-forms composite-component custom-component

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

  1. 字符串列表 - >字段名称
  2. <String, Value> - &gt;列表<fieldName, fieldValue>
  3. 的字段组

    示例值:

    1. [Street, Country, State, ZipCode]
    2. [{(Street, Greenfield), (Country, USA)}, {(Country, Canada), (ZipCode, 3333)}]
    3. 组件将根据以下属性呈现此内容:

      enter image description here

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

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

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

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

      感谢您阅读这篇文章! : - )

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

      复合组件代码:

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

1 个答案:

答案 0 :(得分: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>