この章では、ADF Faces dynamicComponentをフォームや表とともに使用する方法と、これをサポートするためのAttributesModelを作成する方法を説明します。アプリケーションでFusionテクノロジ・スタック全体を使用する場合は、モデルは自動的に作成されるので、データ・コントロールを使用して動的コンポーネントを作成できます。詳細は、『Oracle Application Development FrameworkによるFusion Webアプリケーションの開発』の「データバインドされた基本的なページの作成」および「ADFによるデータバインドされた表の作成」の章を参照してください。
この章は次の項で構成されています。
実行時にどのコンポーネントが必要になるかを、開発時に特定できないこともあります。たとえば、ビジネス・オブジェクトが保持する属性が有効であるのは特定の条件のときに限られており、その属性が必要なときにのみ表示されるようにしたい場合です。標準のコンポーネントを使用するときは、特定のフィールドを表示するかどうかを判定するために、複雑なロジックが必要になる可能性があります。
動的インタフェースが必要になるもう1つの例は、複数のページで同じデータ・ソースが使用されている場合です。オブジェクトの属性が変更される可能性が高い場合は、そのオブジェクトにバインドされているすべてのページに変更を加えることが必要になります。
ADF Facesには動的コンポーネントがあり(af:dynamicComponent)、どのコンポーネントを表示するか、およびその値を、実行時に決定することができます。このコンポーネントによって表示されるのは、レンダリングされたインスタンスそれぞれの、必要な属性のみです。さらに、関連付けられたビジネス・サービスに変更が加えられたときは、その変更が動的コンポーネントによって反映されるので、UIコードの変更は必要ありません。
動的コンポーネントは、フォームまたは表として使用できます。実行時に、必要なコンポーネントがフォームまたは表の中で、動的コンポーネントのかわりにレンダリングされます。どのコンポーネントがレンダリングされるかは、属性のデータ型に基づいて決定されます。たとえば、属性がString型の場合は、inputTextコンポーネントが使用されます。Date型の場合は、inputDateコンポーネントが使用されます。次に示すコンポーネントが動的コンポーネントでサポートされます。
inputText
inputDate
inputListOfValues
selectOneChoice
selectManyChoice
selectOneListbox
selectManyListbox
selectOneRadio
selectBooleanRadio
selectBooleanCheckbox
selectManyCheckbox
フォームの場合は、動的コンポーネントはイテレータ・コンポーネントの中にラップされます。コレクションベース・コンポーネントと同様に、イテレータはコレクション全体にバインドされます。この場合のコレクションとは、AttributesModelオブジェクトの属性の中のコレクションです。イテレータは、モデルの各インスタンスのスタンプ処理を行い、現在のインスタンスのデータをvar属性にコピーします。動的コンポーネントは、各インスタンスのこのvar値にattributeModel属性を使用してアクセスし、その情報に基づいて、使用するコンポーネントのタイプとその構成方法および値を決定します。
たとえば、フォームを作成して従業員のデータを表示するとします(図21-1を参照)。
AttributesModelを作成し、表示する属性それぞれの情報をこの中に保持します。さらに、各インスタンスの値にアクセスする手段も作成します。その後で、この動的コンポーネントのみを使用してフォームを作成します(例21-1を参照)。
例21-1 フォームで使用されている動的コンポーネント
<af:panelFormLayout id="pf1">
  <af:iterator value="#{TestDynCompBean.attributesModel.attributes}" 
               var="attr" id="dyit1">
    <af:dynamicComponent value="#{TestDynCompBean.value[attr.name]}" id="dyipt3"
                         attributeModel="#{attr}"/>
  </af:iterator>
</af:panelFormLayout>
静的な表の場合は、個々の列およびその列の中のコンポーネントが、設計時に静的にページ内で定義されます。動的な表の場合は、列の数とその列の中のコンポーネントの両方が実行時に動的に、次に示すコンポーネントを使用して定義されます。
af:table: 表を定義します。値を取得する方法も、var属性を使用して定義されます(詳細は、第12章「表、ツリー、およびその他のコレクションベースのコンポーネントの使用」を参照してください)。
af:iterator: 属性のコレクションを定義します。列1個と、各列の中のコンポーネント1個が属性ごとに作成されます。
af:column: 列を定義します。この列は、属性ごとに1回スタンプされます。イテレータ内に属性が10個ある場合は、列は10個となり、すべての列が同じ列定義からスタンプされます。
af:dynamicComponent: その列のコンポーネントを定義します。型や値などはその属性から取得されます。
例21-2に、表で使用されている動的コンポーネントを示します。
例21-2 表で使用されている動的コンポーネント
<af:table value="#{TestDynCompBean.values}" var="row"
          varStatus="vs" rowSelection="single"
          id="t1" width="100%">
  <af:iterator value="#{TestDynCompBean.attributesModel.attributes}" id="itr1"
               var="col">
    <af:column headerText="#{col.label}" id="c1">
      <af:dynamicComponent value="#{row[col.name]}"
                           attributeModel="#{col}" id="dc1"/>
    </af:column>
  </af:iterator>
</af:table>
動的コンポーネントを使用して、属性のグルーピングを作成することもできます。たとえば、動的コンポーネントを使用して作成するフォームに、従業員1人の属性を表示するとします。従業員情報(氏名、給与など)を1つのグループにまとめて、部署情報(部署名、部署番号など)を別のグループにまとめます。「Employee Info」というカテゴリと、「Department Info」というカテゴリを作成します。AttributesModelの中で、Employeeオブジェクトの属性を各カテゴリに割り当てます。これらのカテゴリは、AttributesModelオブジェクトのhierarchicalAttributesプロパティの中に保持されます。
グループをページ上で作成するには、ファセット2個を持つスイッチャ・コンポーネントを使用します。最初のファセットは、カテゴリの1つに属するすべての属性を処理し、2つ目のファセットは「フラット」グループ(つまり、どのカテゴリにも属していない属性)を処理します。
グループを使用するときは、メイン・イテレータはAttributesModelのattributesプロパティではなくhierarchicalAttributesプロパティにバインドされます。このプロパティで、ルート・レベルの属性が定義されます。イテレータがコレクションの内容を反復処理するときに、カテゴリの値はattrという名前の変数で保持されます。最初のグループでは、イテレータは変数attrにバインドされ、この反復処理を行い、ディスクリプタ(そのカテゴリに属する子属性のリスト)の値を変数nestedAttrで保持します。子動的コンポーネントは、この変数にアクセスして、レコードごとに表示するコンポーネントのタイプと値を特定します(例21-3を参照)。
例21-3 グループで使用されている動的コンポーネント
<af:panelFormLayout id="pf1">
  <af:iterator value="#{TestDynCompBean.attributesModel.hierarchicalAttributes}"
               var="attr" id="dyit1">
    <af:switcher id="sw" facetName="#{attr.descriptorType}"
                 defaultFacet="ATTRIBUTE">
      <f:facet name="GROUP">
        <af:group id="gg" title="#{attr.label}">
          <af:outputText value="#{attr.label}" id="ot2"/>
          <af:iterator id="it2" value="#{attr.descriptors}" var="nestedAttr">
            <af:dynamicComponent
                 value="#{TestDynCompBean.value[nestedAttr.name]}" id="ndync1"
                 attributeModel="#{nestedAttr}" />
          </af:iterator>
        </af:group>
      </f:facet>
      <f:facet name="ATTRIBUTE">
        <af:dynamicComponent value="#{TestDynCompBean.value[attr.name]}"
                             id="iinerit1" attributeModel="#{attr}"/>
      </f:facet>
    </af:switcher>
  </af:iterator>
</af:panelFormLayout>
メイン・イテレータは、attributeModel内のルート・レベル属性を反復処理します。ルート属性のうち、どのグループにも属していないもの(つまり、Attributeタイプのルート属性)については、その属性に対応する動的コンポーネントがATTRIBUTEファセット内に作成されます。ルート属性のうち、その下に属性があるもの(つまり、Groupタイプのルート属性)については、その属性がGROUPファセットに追加されます。そのファセットの中で、別のイテレータがそのグループ内の標準属性のそれぞれを反復処理し、標準属性のそれぞれに基づいて動的コンポーネントを作成します。
AttributesModelクラスは属性のコレクションであり、各属性はBaseAttributeDescriptorオブジェクトによって表現されます。このオブジェクトはメタデータを保持しており、動的コンポーネントはこのメタデータを使用してデータの表示方法を決定します。たとえば、コンポーネントのタイプ、名前、ラベル、説明です。開発者は、BaseAttributeDescriptorクラスおよびAttributesModelクラスを拡張して、動的コンポーネントに必要なデータを提供する必要があります。
グループを動的コンポーネントとともに使用する場合は、GroupAttributeDescriptorオブジェクトも作成する必要があります。
モデルを作成するには、BaseAttributeDescriptorオブジェクト、AttributesModelオブジェクトおよびマネージドBeanをページ用に作成する必要があります。動的コンポーネントとイテレータは、これらを使用して属性のデータとメタデータにアクセスします。
始める前に
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。詳細は、21.1項「実行時の動的コンポーネントの決定について」を参照してください。
モデルを作成する手順:
属性の各プロパティを記述する、属性定義クラスを作成します。このメタデータが、動的コンポーネントによってどのデータを表示するか、およびどのように構成するかを決定するときに使用されます。たとえば、この定義クラスには、属性の次に示すプロパティの取得メソッドがあると考えられます。
name
label
dataType
属性定義クラスの例は、oracle.adfdemo.view.feature.rich.dynamicFacesパッケージのTestDynamicComponentPageDefクラスのTestAttributeDef内部クラスを参照してください。このパッケージは、ADF Facesアプリケーションの「アプリケーション・ソース」ディレクトリにあります。
各属性を定義する、別のクラスを作成します。この定義には、手順1で作成した定義クラスを使用します。このクラスは、各属性を定義してから、そのメタデータが入力された状態で属性のリストを返す必要があります。
たとえば、Employeeオブジェクトの属性としては次のものが考えられます。
Ename
Empno
Deptname
Deptno
Manager
例21-4に、属性定義の作成方法の例を示します。これには、手順1で作成されたメタデータが使用されています。
例21-4 属性定義の例
public void addAttributeDef (String name, String label, Class dataType) {
  TestAttributeDef attributeDef = new TestAttributeDef(name, label, dataType);
    _attributes.put(name, attributeDef);
 }
例21-5は、Employeeオブジェクトの属性のリストを、属性定義が入力された状態で返す方法を示します。
例21-5 属性の定義
public void setupAttributes()
{
  _attributes = new HashMap<String, TestAttributeDef>();
    addAttributeDef("Ename", "Employee Name", null, "Name", 10, 20, String.class);
    addAttributeDef("Empno", "Employee Number", null,
                      "Employee Number", 10, 20, Number.class);
   addAttributeDef("Deptname", "Department Name", null, "Department Name", 10, 20, String.class);
   addAttributeDef("Deptno", "Department Number", null, "Department Number", 10, 20, Number.class);
   addAttributeDef("Manager", "Manager", null, "Manager", 10, 20, Number.class);
}
属性定義クラス全体の例は、oracle.adfdemo.view.feature.rich.dynamicFacesパッケージのTestDynamicComponentPageDefクラスを参照してください。このパッケージは、ADF Facesアプリケーションの「アプリケーション・ソース」ディレクトリにあります。
BaseAttributeDescriptorオブジェクトのためのクラスを作成します。このクラスは、BaseAttributeDescriptorクラスを拡張する必要があります。また、各属性のメタデータ・プロパティにアクセスする必要があります。例21-6に、NameおよびDataTypeを返す方法の例を示します。
例21-6 属性定義へのアクセス
public class TestAttributeDescriptor extends BaseAttributeDescriptor {
  public TestAttributeDescriptor(TestAttributeDef attributeDef) {
    _attributeDef = attributeDef;
  }
 
  public Object getId() {
    return getName();
  }
 
  public String getName() {
    return _attributeDef.getName();
  }
 
  public Class getDataType() {
    return _attributeDef.getDataType();
  }
完全な例については、oracle.adfdemo.view.feature.rich.dynamicFacesパッケージのTestDynamicComponentBeanマネージドBeanのTestAttributeDescriptor内部クラスを参照してください。このパッケージは、ADF Facesアプリケーションの「アプリケーション・ソース」ディレクトリにあります。
AttributesModelクラスを拡張するクラスを作成します。このクラスでは、属性をBaseAttributeDescriptorオブジェクトからリストとして作成する必要があります。
例21-7 AttributesModelの作成
public class TestAttributesModel extends AttributesModel {
  public TestAttributesModel() {
    _flatAttributes = new ArrayList<BaseAttributeDescriptor>();
  }
 
  public List<BaseAttributeDescriptor> getAttributes() {
    return _flatAttributes;
  private void _setupAttributesFromDefinition() {
    Map<String, List<BaseAttributeDescriptor>>();
    List<TestDynamicComponentPageDef.TestAttributeDef> attributeList = _pageDef.getAttributeDefs();
 . . .
      for (TestDynamicComponentPageDef.TestAttributeDef demoAttrDef : attributeList) {
        TestAttributeDescriptor attrDesc = new TestAttributeDescriptor(demoAttrDef);
        _flatAttributes.add(attrDesc);
        }
 
  }
}
完全な例は、oracle.adfdemo.view.feature.rich.dynamicFacesパッケージのTestDynamicComponentBeanマネージドBeanのTestAttributesModel内部クラスを参照してください。このパッケージは、ADF Facesアプリケーションの「アプリケーション・ソース」ディレクトリにあります。
マネージドBeanを作成します。このマネージドBeanは、ページのAttributesModelオブジェクトを、値を設定した状態で返す必要があります。また、そのページに必要なロジックがある場合は、そのロジックを実行する必要があります。たとえば、動的コンポーネントをフォームの中で使用する場合に、ユーザーが前後のレコードに移動できるようにするには、そのロジックを開発者が用意する必要があります。例21-8に示すコードは、AttributesModelを返すものであり、さらに前後のレコードにアクセスするためのロジックをActionイベントを使用して定義しています。
例21-8 動的コンポーネントのマネージドBeanのコード
public class TestDynamicComponentBean {
  public TestDynamicComponentBean() {
    _attrsModel = new TestAttributesModel();
  }
 
  public AttributesModel getAttributesModel() {
    return _attrsModel;
  }
 
  public Map[] getValues() {
    return _DATA;
  }
  public Map getValue() {
   return _DATA[currentRowIndex];
  }
 
  public void next(ActionEvent actionEvent) {
    if (currentRowIndex < _DATA.length - 1)
        currentRowIndex++;
  }
 
  public boolean getNextEnabled() {
    return (currentRowIndex < (_DATA.length - 1));
  }
 
  public void previous(ActionEvent actionEvent) {
    if (currentRowIndex > 0)
        currentRowIndex--;
  }
 
  public boolean getPreviousEnabled() {
    return currentRowIndex > 0;
  }
完全な例(マネージドBeanによってAttributesModelのデータが設定される方法を含む)は、oracle.adfdemo.view.feature.rich.dynamicFacesパッケージのTestDynamicComponentBeanマネージドBeanを参照してください。このパッケージは、ADF Facesアプリケーションの「アプリケーション・ソース」ディレクトリにあります。
グループを動的コンポーネントとともに使用する場合は、GroupAttributeDescriptorオブジェクトも作成する必要があります。このオブジェクトが、グループ情報に必要なメタデータを保持します。たとえば、グループに属する属性のリストです。開発者は、イテレータおよび動的コンポーネントによってグループを表示するために必要となるロジックも用意する必要があります。
始める前に
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。詳細は、21.1項「実行時の動的コンポーネントの決定について」を参照してください。
グループを使用するモデルを作成する手順:
21.2.1項「グループのないモデルの作成方法」の手順1の説明に従って、属性定義クラスを作成します。ただし、categoryの属性定義をStringとして指定します。このカテゴリが、グループの定義に使用されます。
属性を作成するときに、カテゴリを必要とする属性に対してカテゴリの値を割り当てます。たとえば、「Employee Personal」という値をEmpname属性およびEmpno属性に割り当てて、「Department Info」という値をDeptno属性およびDeptname属性に割り当てます。
categoryをBaseAttributeDescriptorクラスの一部とするために、getメソッドを用意します。ただし、このgetメソッドのシグネチャはgetGroupNameとしてください。例21-9に、getメソッドのコーディング例を示します。
GroupAttributeDescriptorオブジェクトのクラスを作成します。このクラスは、GroupAttributeDescriptorを拡張します。このオブジェクトは、グループの名前と、グループ内の属性のリストを保持します。例21-10に、GroupAttributeDescriptorクラスを示します。
例21-10 GroupAttributeDescriptorオブジェクトのクラス
public class TestGroupAttributeDescriptor extends GroupAttributeDescriptor {
  public TestGroupAttributeDescriptor(String groupName, List<BaseAttributeDescriptor> attributeList) {
     _groupName = groupName;
    _flatAttributes = attributeList;
  }
 
  @Override
  public String getName() {
    return _groupName;
  }
 
  public List<? extends Descriptor> getDescriptors() {
    return _flatAttributes;
  }
 
  public String getDescription() {
    return "This is a group";
  }
 
  public String getLabel() {
    return _groupName;
  }
 
  private List<BaseAttributeDescriptor> _flatAttributes;
  private String _groupName;
 
}
作成するAttributesModelクラスの中で、グループを表すhierarchicalAttributesを追加します。このようにするには、たとえばBaseAttributeDescriptorオブジェクトを調べるロジックを追加し、このオブジェクトにグループ名が格納されている場合に、その名前をhierarchicalAttributesオブジェクトに追加します。例21-11に、このロジックのコーディング例を示します。
例21-11 グループをhierarchicalAttributesに追加するロジック
 for (TestDynamicComponentPageDef.TestAttributeDef demoAttrDef : attributeList) {
  TestAttributeDescriptor attrDesc = new TestAttributeDescriptor(demoAttrDef);
    _flatAttributes.add(attrDesc);
    String groupName = attrDesc.getGroupName();
    if (groupName != null && !groupName.isEmpty()) {
      List<BaseAttributeDescriptor> list = groupMap.get(groupName);
        if (list == null) {
          list = new ArrayList<BaseAttributeDescriptor>();
          groupMap.put(groupName, list);
        }
        list.add(attrDesc);
      } else {
        _hierAttributes.add(attrDesc);
      }
    }
 
  for (String groupName : groupMap.keySet()) {
    TestGroupAttributeDescriptor groupMetadata = 
      new TestGroupAttributeDescriptor(groupName, groupMap.get(groupName));
    _hierAttributes.add(groupMetadata);
  }
}
完全な例は、oracle.adfdemo.view.feature.rich.dynamicFacesパッケージのTestDynamicComponentBeanマネージドBeanのTestAttributesModel内部クラスを参照してください。このパッケージは、ADF Facesアプリケーションの「アプリケーション・ソース」ディレクトリにあります。
動的コンポーネントをフォームの中で使用するときは、イテレータを組み込む必要があります。このイテレータがAttributesModelにアクセスして属性とその定義を取得します。動的コンポーネントは、このイテレータによってスタンプ・アウトされた各インスタンスの情報を取得して、どのコンポーネントを使用するか、およびどのように構成するかを特定します。
フォーム内の属性をグループ化する場合は、ファセット2個を持つスイッチャ・コンポーネントも使用する必要があります。ファセットの1つは、グループを対応する属性とともに表示するものであり、もう1つのファセットはどのグループにも属していない属性を表示します。
動的コンポーネントをフォームの中で使用するには、panelFormLayoutコンポーネント、イテレータおよびその動的コンポーネントを使用します。フォーム内のレコード間をナビゲートできるようにする場合は、ボタンも使用する必要があります。
始める前に
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。詳細は、21.1項「実行時の動的コンポーネントの決定について」を参照してください。
動的コンポーネントをグループなしでフォームとしてページに追加する手順:
panelFormLayoutコンポーネントを作成します。手順は9.7項「フォームでのコンテンツの配置」を参照してください。
「コンポーネント」ウィンドウの「操作」パネルから、「イテレータ」をpanelFormLayoutコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで次のとおりに設定します。
Value: EL式を指定します。この式を解決した結果がAttributesModelオブジェクトのattributesプロパティとなる必要があります。次に例を示します。
#{TestDynCompBean.attributesModel.attributes}"
Var: モデルの属性へのアクセスに使用できるString。例: attr
「コンポーネント」ウィンドウから、「動的コンポーネント」をiteratorコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで次のとおりに設定します。
AttributeModel: EL式を指定します。この式を解決した結果は、イテレータ用に作成された変数となる必要があります。たとえば#{attr}です。
Value: EL式を指定します。この式を解決した結果は、AttributesModelオブジェクトの各属性名となる必要があります。次に例を示します。
#{TestDynCompBean.value[attr.name]}"
レコード間を移動するためのロジックを用意する場合は、ボタンをpanelGroupLayoutコンポーネントの中で追加し、アクション・イベントを使用して前後のレコードにアクセスします。ボタンの使用方法の詳細は、20.3.1項「ボタンおよびリンクをナビゲーションとActionEventの配信に使用する方法」を参照してください。
例21-12に示すボタンのactionListener属性は、マネージドBeanのロジックにバインドされており、このロジックによってモデル内のレコード間をナビゲートします。
例21-12 ボタンを使用してAttributesModel内のレコード間をナビゲートする
<af:panelGroupLayout layout="horizontal" id="pgl2">
  <af:button text="Previous" id="cb2" actionListener="#{TestDynCompBean.previous}"
             disabled="#{!TestDynCompBean.previousEnabled}"/>
  <af:button text="Next" id="cb1" actionListener="#{TestDynCompBean.next}"
             disabled="#{!TestDynCompBean.nextEnabled}"/>
</af:panelGroupLayout>
例21-13に、対応するマネージドBeanコードを示します。
例21-13 動的コンポーネントの次レコードにアクセスするためのマネージドBeanコード
public Map[] getValues() {
  return _DATA;
}
 
public Map getValue() {
  return _DATA[currentRowIndex];
}
public void next(ActionEvent actionEvent) {
  if (currentRowIndex < _DATA.length - 1)
      currentRowIndex++;
}
 
public boolean getNextEnabled() {
  return (currentRowIndex < (_DATA.length - 1));
}
フォーム上の属性を動的コンポーネントを使用してグループ化するときは、グループに属する属性をフォーム上のある部分に配置し、どのグループにも属していない属性を別の部分に配置する必要があります。スイッチャ・コンポーネントのファセットを使用して、この2つを分離します。
スイッチャ・コンポーネントは、イテレータ・コンポーネントの子です。ただし、このイテレータは、AttributesModelの属性にバインドされるのではなく、モデルのhierarchicalAttributesにバインドされ、オブジェクトを自身の変数内に格納します。スイッチャのファセット内にある別のイテレータが、このhierarchicalAttributesオブジェクトの中にあるディスクリプタにバインドされます。このイテレータから、動的コンポーネントの情報が取得されます。
始める前に
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。詳細は、21.1項「実行時の動的コンポーネントの決定について」を参照してください。
動的コンポーネントをグループ付きでフォームとしてページに追加する手順:
panelFormLayoutコンポーネントを作成します。手順は9.7項「フォームでのコンテンツの配置」を参照してください。
「コンポーネント」ウィンドウの「操作」パネルから、「イテレータ」をpanelFormLayoutコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで、次を設定します。
Value: EL式を指定します。この式を解決した結果がAttributesModelオブジェクトのhierarchicalAttributesプロパティとなる必要があります。次に例を示します。
#{TestDynCompBean.attributesModel.hierarchicalAttributes}"
Var: モデルの属性へのアクセスに使用できるString。例: attr
「スイッチャ」をiteratorコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで、次を設定します。
FacetName: EL式を入力します。この式を解決した結果は、親イテレータの変数によって返される値のdescriptorTypeプロパティとなる必要があります。次に例を示します。
#{attr.descriptorType}
DefaultFacet: #{attr.descriptorType}によって返されず、定義済ファセットのどれにも一致しない属性を保持するファセットの名前。たとえば、ATTRIBUTEです。
「構造」ウィンドウで、スイッチャ・コンポーネントを右クリックして「スイッチャの中に挿入」→「ファセット」を選択します。
「ファセットの挿入」ダイアログで、ファセットの名前をGROUPと入力します。作成されたファセットには、グループに属する属性が格納されます。
「コンポーネント」ウィンドウの「テキストおよび選択」パネルから、「出力テキスト」をドラッグ・アンド・ドロップします。このコンポーネントによってグループ名が表示されます。
「プロパティ」ウィンドウで、「値」を、返されるグループのlabelプロパティにバインドします。これには、親イテレータの変数を使用します。たとえば、#{attr.label}です。
「イテレータ」をoutputTextコンポーネントに子としてドラッグ・アンド・ドロップします。このイテレータは各グループ内の属性を反復処理するものであり、動的コンポーネントはこのイテレータを使用してコンポーネントおよび値を表示します。
「プロパティ」ウィンドウで、次を設定します。
Value: EL式を入力します。この式を解決した結果は、最初のイテレータによってその変数を使用して返されるディスクリプタ・オブジェクトとなる必要があります。たとえば、#{attr.descriptors}です。
Var: ディスクリプタ内の属性へのアクセスに使用できるString。例: nestedAttr
「動的コンポーネント」を2つ目のイテレータに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで次のとおりに設定します。
AttributeModel: EL式を入力します。この式を解決した結果は、2つ目のイテレータ用に作成された変数となる必要があります。たとえば、#{nestedAttr}です。
Value: EL式を指定します。この式を解決した結果は、2つ目のイテレータによって返される各属性名となる必要があります。次に例を示します。
#{TestDynCompBean.value[nestedAttr.name]}
「構造」ウィンドウで、outputTextコンポーネントとiteratorコンポーネントを選択して右クリックし、「囲む」を選択します。「囲む」ダイアログで、「グループ」を選択して「OK」をクリックします。
「プロパティ」ウィンドウで、「タイトル」を、最初のイテレータによって返されるグループのラベル・プロパティにバインドします。たとえば、#{attr.label}です。
別のファセットを、スイッチャ・コンポーネントに子としてドラッグ・アンド・ドロップします。このファセットの名前を「ATTRIBUTE」と入力します。
別の「動的コンポーネント」をATTRIBUTEファセットに子としてドラッグ・アンド・ドロップし、次のとおりに設定します。
AttributeModel: EL式を指定します。この式を解決した結果は、メイン・イテレータ用に作成された変数となる必要があります。たとえば#{attr}です。
Value: EL式を指定します。この式を解決した結果は、メイン・イテレータによって返される各属性名となる必要があります。次に例を示します。
#{TestDynCompBean.value[attr.name]}
動的コンポーネントを表の中で使用するときは、表の列をイテレータの中にラップする必要があります。このイテレータがAttributesModelにアクセスして属性とその定義を取得します。この情報を使用して、列のヘッダー・テキストが決定されます。動的コンポーネントは、イテレータによってスタンプ・アウトされた属性インスタンスごとに情報を取得して、どのコンポーネントを使用するか、およびどのように構成するかを特定すると同時に、表の変数を使用して、どのデータを表示するかを決定します。
表内の属性をグループ化する場合は、ファセットを2つ持つスイッチャ・コンポーネントも使用する必要があります。ファセットの1つは、グループを対応する属性とともに表示するものであり、もう1つのファセットはどのグループにも属していない属性を表示します。
動的コンポーネントを表の中で使用するには、表コンポーネントをデータにバインドします。columnコンポーネントのかわりに、イテレータが表の動的な子となり、このイテレータはAttributesModelのattributesプロパティにバインドされます。列は、このイテレータの子です。動的コンポーネントは、列の子です。
始める前に
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。詳細は、21.1項「実行時の動的コンポーネントの決定について」を参照してください。
動的コンポーネントをグループなしで表としてページに追加する手順:
「コンポーネント」ウィンドウの「データ・ビュー」パネルから、「表」をドラッグ・アンド・ドロップし、表のデータにバインドします。
表の詳細は、12.3項「表へのデータの表示」を参照してください。
「構造」ウィンドウで、自動的に作成された列コンポーネントとその内容を削除します。後の手順で、列を手動で追加します。
「コンポーネント」ウィンドウの「操作」パネルから、「イテレータ」をtableコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで次のとおりに設定します。
Value: EL式を指定します。この式を解決した結果がAttributesModelオブジェクトのattributesプロパティとなる必要があります。次に例を示します。
#{TestDynCompBean.attributesModel.attributes}"
Var: モデルの属性へのアクセスに使用できるString。例: col
「コンポーネント」ウィンドウから、「列」をイテレータ・コンポーネントに子としてドラッグ・アンド・ドロップします。「プロパティ」ウィンドウで、HeaderTextを、イテレータによって返される属性のlabelプロパティにバインドします。たとえば、#{col.label}です。
「コンポーネント」ウィンドウから、「動的コンポーネント」をcolumnコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで次のとおりに設定します。
AttributeModel: EL式を指定します。この式を解決した結果は、イテレータ用に作成された変数となる必要があります。たとえば#{col}です。
Value: EL式を指定します。この式を解決した結果は、AttributesModelオブジェクトの各属性名となる必要があります。これは、行ごとにスタンプ・アウトされる必要があるため、表コンポーネントから返される値にこれをバインドする必要があります。たとえば、#{row[col.name]}です。
表の中の属性を動的コンポーネントを使用してグループ化するときは、グループが親列として表示されます。図21-2に示すEmployeeオブジェクトの特定の属性は、「Employee Personal」グループおよび「Department Info」グループに属しています。
スイッチャ・コンポーネントを使用して、グループに属している属性とそうでない属性とを分離します。ただし、このメイン・イテレータは、AttributesModelの属性にバインドされるのではなく、モデルのhierarchicalAttributesにバインドされ、オブジェクトを自身の変数内に格納します。スイッチャのファセット内にある別のイテレータが、このhierarchicalAttributesオブジェクトの中にあるディスクリプタにバインドされます。このイテレータから動的コンポーネントの情報が取得されて、コンポーネントに属性のグループを表示できるようになります。
AttributeModelのhierarchicalAttributesによって、AttributeModelのルート・レベルの属性が定義されます。ルート・レベルの属性が通常の属性である場合、つまりその属性のタイプがATTRIBUTEである場合は、この属性はどのグループにも属しておらず、表ではその属性に対して1つの列がレンダリングされます。ルート・レベルの属性がグループ化された属性である場合、つまり属性のタイプがGROUPである場合は、このグループに属している通常の属性のリストが存在します。ファセット内のイテレータは、このグループを反復処理し、そのグループの中の各属性は列としてスタンプされます。たとえば、「Employee Personal」はGROUPタイプの属性であり、この中には通常の属性が3つあります。「Employee Number」、「Name」および「Salary」です(図21-2を参照)。
始める前に
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。詳細は、21.1項「実行時の動的コンポーネントの決定について」を参照してください。
動的コンポーネントをグループ付きで表としてページに追加する手順:
「コンポーネント」ウィンドウの「データ・ビュー」パネルから、「表」をドラッグ・アンド・ドロップします。「ADF Faces表の作成」ダイアログで、「データを今すぐバインド」を選択します。「表データ・コレクション」の「参照」をクリックして「表データ・コレクションの選択」ダイアログを開きます。モデル用に作成したマネージドBeanのvaluesプロパティを選択します。
表の詳細は、12.3項「表へのデータの表示」を参照してください。
「構造」ウィンドウで、自動的に作成された列コンポーネントとその内容を削除します。後の手順で、列を手動で追加します。
「コンポーネント」ウィンドウの「操作」パネルから、「イテレータ」をtableコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで次のとおりに設定します。
Value: EL式を指定します。この式を解決した結果がAttributesModelオブジェクトのhierarchicalAttributesプロパティとなる必要があります。次に例を示します。
#{TestDynCompBean.attributesModel.heirarchicalAttributes}"
Var: モデルの属性へのアクセスに使用できるString。例: column
「コンポーネント」ウィンドウから、「列」をイテレータ・コンポーネントに子としてドラッグ・アンド・ドロップします。「プロパティ」ウィンドウで、HeaderTextを、イテレータによって返されるグループのlabelプロパティにバインドします。たとえば、#{column.label}です。
「スイッチャ」をcolumnコンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで、次を設定します。
FacetName: EL式を指定します。この式を解決した結果は、親イテレータの変数によって返される値のdescriptorTypeプロパティとなる必要があります。次に例を示します。
#{column.descriptorType}
DefaultFacet: どのグループにも属していない属性を保持するファセットの名前。たとえばATTRIBUTEです。
「構造」ウィンドウで、スイッチャ・コンポーネントを右クリックして「スイッチャの中に挿入」→「ファセット」を選択します。
「ファセットの挿入」ダイアログで、ファセットの名前をGROUPと入力します。作成されたファセットには、グループに属する属性が格納されます。
「イテレータ」を、GROUP facetコンポーネントに子としてドラッグ・アンド・ドロップします。このイテレータは各グループ内の属性を反復処理するものであり、動的コンポーネントはこのイテレータを使用してコンポーネントおよび値を表示します。
「プロパティ」ウィンドウで、次を設定します。
Value: EL式を指定します。この式を解決した結果は、最初のイテレータによってイテレータの変数を使用して返されるDescriptorオブジェクトとなる必要があります。たとえば、#{column.descriptors}です。
Var: ディスクリプタ内の属性へのアクセスに使用できるString。例: nestedCol
「列」をイテレータ・コンポーネントに子としてドラッグ・アンド・ドロップします。「プロパティ」ウィンドウで、HeaderTextを、親イテレータによって返される属性のlabelプロパティにバインドします。たとえば、#{nestedCol.label}です。
「動的コンポーネント」を2つ目のイテレータに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウで次のとおりに設定します。
AttributeModel: EL式を指定します。この式を解決した結果は、2つ目のイテレータ用に作成された変数となる必要があります。たとえば、#{nestedCol}です。
Value: EL式を指定します。この式を解決した結果は、2つ目のイテレータによって返される各属性名となる必要があります。次に例を示します。
#{row[nestedCol.name]}
別の「ファセット」を、スイッチャ・コンポーネントに子としてドラッグ・アンド・ドロップします。このファセットの名前を「ATTRIBUTE」と入力します。
別の「動的コンポーネント」をATTRIBUTEファセットに子としてドラッグ・アンド・ドロップし、次のとおりに設定します。
AttributeModel: EL式を指定します。この式を解決した結果は、メイン・イテレータ用に作成された変数となる必要があります。たとえば#{column}です。
Value: EL式を指定します。この式を解決した結果は、メイン・イテレータによって返される各属性名となる必要があります。次に例を示します。
#{row[column.name]}
変換および検証を動的コンポーネントに追加するには、必要なコンバータまたはバリデータのタグを追加し、どの属性を検証または変換するかを指定します。enabled属性のかわりに、動的コンポーネントではdisabled属性が使用されます。
始める前に
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。詳細は、21.1項「実行時の動的コンポーネントの決定について」を参照してください。
バリデータまたはコンバータを動的コンポーネントとともに使用する手順:
「コンポーネント」ウィンドウの「操作」パネルから、必要なコンバータまたはバリデータを動的コンポーネントに子としてドラッグ・アンド・ドロップします。
「プロパティ」ウィンドウの「その他」セクションで、「無効」フィールドにマウスを置いたときに表示されるアイコンをクリックして「式ビルダー」を選択します。
式ビルダーで、解決した結果が属性となる式を入力し、必要なパターンを指定します。例21-14に2つのコンバータとバリデータを示します。これらは、動的コンポーネントによって表現される様々な属性に使用されるものの例です。DateTimeコンバータはHiredate属性に対して実行され、NumberコンバータはSal属性に対して実行され、LengthバリデータはJob属性に対して実行され、LongRangeバリデータはSal属性に対して実行されます。
例21-14 動的コンポーネントの検証と変換
<af:dynamicComponent value="#{DynCompBean.value[attr.name]}"
                     attributeModel="#{attr}" id="dc1"/>
  <af:convertDateTime disabled="#{attr.name == 'Hiredate' ? false : true}"
                      pattern="yyyy/MM/dd"/>
  <af:convertNumber disabled="#{attr.name == 'Sal' ? false : true}"
                    pattern="#,###,###" />
  <af:validateLength disabled="#{attr.name == 'Job' ? false : true}"
                     maximum="10" hintMaximum="maxmum length is 10"/>
  <af:validateLongRange disabled="#{attr.name == 'Sal' ? false : true}"
                        minimum="1000"/>
</af:dynamicComponent>
動的フォームを作成することは、実質的には動的にレンダリングされるコンポーネントのブロックを作成することです。静的コンポーネントをこのコンポーネントのブロックの前または後に配置できますが、静的コンポーネントをそのブロックの中に配置することはできません。
このような制約はありますが、多数の動的および静的のコンポーネントを使用して複雑なフォームを作成できます。また、静的コンポーネントを、詳細なレベルの動的コンポーネントどうしの間に配置することもできます。
たとえば、フォームに名前と住所の情報を、英語と日本語の両方で表示する必要があるとします。この例では、日本語の情報は動的コンポーネントを使用して表示し、英語の情報は静的コンポーネントで表示するとします。図21-3に、フィールドの配置の例を示します。動的な日本語コンテンツを、静的コンテンツの後に表示しています。
例21-15に、このフォームを作成する方法の例を示します。静的なinputTextコンポーネントと動的コンポーネントを使用して、NameグループおよびAddressグループの属性にアクセスします。
例21-15 静的コンポーネントの後に動的コンポーネント
<panelFormLayout ... >
  <af:group title="Name">
    <af:inputText value="#{myBean.firstName} id="it1" label="First Name"/>
    <af:inputText value="#{myBean.middleName} id="it2" label="Middle Name"/>
    <af:inputText value="#{myBean.lastName} id="it3" label="Last Name"/>
    <af:iterator
             value="#{DynCompBean.attributesModel.hierarchicalAttributes("Name")}"
                 var="attr" id="iter1">
      <af:dynamicComponent id="dc1"
                           value="#{DynCompBean.value[attr.name]}"
                           attributeModel="#{attr}"/>
    </af:iterator>
  </af:group>
  <af:group title="Address">
    <af:inputText value="#{myBean.streetAddress}" id="it4" 
                  label="Street Address"/>
    <af:inputText value="#{myBean.City.inputValue}" id="it5" label="City"/>
    <af:inputText value="#{myBean.State.inputValue}" id="it6" label="State"/>
    <af:iterator
          value="#{DynCompBean.attributesModel.hierarchicalAttributes("Address")}"
          var="attr" id="iter1">
      <af:dynamicComponent id="dc1"
                         value="#{DynCompBean[attr.name].inputValue}"
                         attributeModel="#{attr}"/>
    </af:iterator>
  </af:group>
</panelFormLayout>
次に、日本語の名前および住所の情報を英語の情報と分離させるかわりに、図21-4に示すように交互に表示するとします。
この場合は、動的コンポーネントの中でグループを使用するかわりに、必要な属性のみ(つまり、全部の属性ではありません)にアクセスします(例21-16を参照)。
例21-16 動的コンポーネントと静的コンポーネント
<af:group title="Name">
  <af:inputText value="#{myBean.firstName} id="it1" label="First Name"/>
  <af:iterator value="#{DynCompBean.attributesModel.attributes("Japanese First Name")}"
               var="attr" id="iter1">
    <af:dynamicComponent id="dc1" value="#{DynCompBean.value[attr.name]}"
                         attributeModel="#{attr}"/>
  </af:iterator>
  <af:inputText value="#{myBean.middleName} id="it2" label="Middle Name"/>
  <af:inputText value="#{myBean.lastName} id="it3" label="Last Name"/>
  <af:iterator value="#{DynCompBean.attributesModel.attributes("Japanese Last Name")}"
               var="attr" id="iter1">
    <af:dynamicComponent id="dc1" value="#{DynCompBean.value[attr.name]}"
                         attributeModel="#{attr}"/>
  </af:iterator>
</af:group>
<af:group title="Address">
  <af:inputText value="#{myBean.streetAddress}" id="it4" label="Street Address"/>
  <af:iterator value="#{DynCompBean.attributesModel.attributes("Japanese Street Address")}"
               var="attr" id="iter1">
    <af:dynamicComponent id="dc1" value="#{DynCompBean.value[attr.name]}"
                         attributeModel="#{attr}"/>
  </af:iterator>
. . .
</af:group>