dynamicComponent
をフォームや表とともに使用する方法と、これをサポートするためのAttributesModel
を作成する方法を説明します。アプリケーションでFusionテクノロジ・スタック全体を使用する場合は、モデルは自動的に作成されるので、データ・コントロールを使用して動的コンポーネントを作成できます。詳細は、『Oracle Application Development FrameworkによるFusion Webアプリケーションの開発』の「データバインドされた基本的なページの作成」および「ADFによるデータバインドされた表の作成」の章を参照してください。
この章は次の項で構成されています。
ADF Facesの動的コンポーネントとは、表示するコンポーネントとその値を、実行時に決定するコンポーネントです。実行時にどんなコンポーネントが必要になるか不確かな場合には、このコンポーネントを使用できます。
実行時にどのコンポーネントが必要になるかを、開発時に特定できないこともあります。たとえば、ビジネス・オブジェクトが保持する属性が有効であるのは特定の条件のときに限られており、その属性が必要なときにのみ表示されるようにしたい場合です。標準のコンポーネントを使用するときは、特定のフィールドを表示するかどうかを判定するために、複雑なロジックが必要になる可能性があります。
動的インタフェースが必要になるもう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
を作成し、表示する属性それぞれの情報をこの中に保持します。さらに、各インスタンスの値にアクセスする手段も作成します。その後で、この動的コンポーネントのみを使用してフォームを作成します(次の例を参照)。
<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属性を使用して定義されます(「表、ツリー、およびその他のコレクションベースのコンポーネントの使用」を参照してください)。
af:iterator
: 属性のコレクションを定義します。列1個と、各列の中のコンポーネント1個が属性ごとに作成されます。
af:column
: 列を定義します。この列は、属性ごとに1回スタンプされます。イテレータ内に属性が10個ある場合は、列は10個となり、すべての列が同じ列定義からスタンプされます。
af:dynamicComponent
: その列のコンポーネントを定義します。型や値などはその属性から取得されます。
次の例に、表で使用されている動的コンポーネントを示します。
<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
で保持します。子動的コンポーネントは、この変数にアクセスして、レコードごとに表示するコンポーネントのタイプと値を特定します(次の例を参照)
<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ファセットに追加されます。そのファセットの中で、別のイテレータがそのグループ内の標準属性のそれぞれを反復処理し、標準属性のそれぞれに基づいて動的コンポーネントを作成します。
ADF Facesには、属性のコレクションを持つAttributeModelクラスが用意されています。これらの各属性はBaseAttributeDescriptorオブジェクトによって記述されます。動的コンポーネントのグループありで、またはグループなしでモデルを作成できます。グループなしのモデルの場合は、BaseAttributeDescriptorオブジェクト、AttributesModelオブジェクト、およびマネージドBeanを作成する必要があります。グループありのモデルの場合は、GroupAttributeDescriptorを作成する必要があります。
AttributesModel
クラスは属性のコレクションであり、各属性はBaseAttributeDescriptor
オブジェクトによって表現されます。このオブジェクトはメタデータを保持しており、動的コンポーネントはこのメタデータを使用してデータの表示方法を決定します。たとえば、コンポーネントのタイプ、名前、ラベル、説明です。開発者は、BaseAttributeDescriptor
クラスおよびAttributesModel
クラスを拡張して、動的コンポーネントに必要なデータを提供する必要があります。
グループを動的コンポーネントとともに使用する場合は、GroupAttributeDescriptor
オブジェクトも作成する必要があります。
モデルを作成するには、BaseAttributeDescriptor
オブジェクト、AttributesModel
オブジェクトおよびマネージドBeanをページ用に作成する必要があります。動的コンポーネントとイテレータは、これらを使用して属性のデータとメタデータにアクセスします。
始める前に:
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。「実行時のコンポーネントの決定について」を参照してください。
モデルを作成する手順:
グループを動的コンポーネントとともに使用する場合は、GroupAttributeDescriptor
オブジェクトも作成する必要があります。このオブジェクトが、グループ情報に必要なメタデータを保持します。たとえば、グループに属する属性のリストです。開発者は、イテレータおよび動的コンポーネントによってグループを表示するために必要となるロジックも用意する必要があります。
始める前に:
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。「実行時のコンポーネントの決定について」を参照してください。
グループを使用するモデルを作成する手順:
ADF Faces panelFormLayoutコンポーネントは、AttributeModelにアクセスして属性とその定義を取得するイテレータです。属性をグループ化しないフォームで動的コンポーネントを使用する場合は、このイテレータを使用する必要があります。動的コンポーネントを使用してフォームで属性をグループ化する場合は、スイッチャ・コンポーネントを使用して、グループ化した属性とグループ化していない属性を分ける必要があります。
動的コンポーネントをフォームの中で使用するときは、イテレータを組み込む必要があります。このイテレータがAttributesModel
にアクセスして属性とその定義を取得します。動的コンポーネントは、このイテレータによってスタンプ・アウトされた各インスタンスの情報を取得して、どのコンポーネントを使用するか、およびどのように構成するかを特定します。
フォーム内の属性をグループ化する場合は、ファセット2個を持つスイッチャ・コンポーネントも使用する必要があります。ファセットの1つは、グループを対応する属性とともに表示するものであり、もう1つのファセットはどのグループにも属していない属性を表示します。
動的コンポーネントをフォームの中で使用するには、panelFormLayout
コンポーネント、イテレータおよびその動的コンポーネントを使用します。フォーム内のレコード間をナビゲートできるようにする場合は、ボタンも使用する必要があります。
始める前に:
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。「実行時のコンポーネントの決定について」を参照してください。
動的コンポーネントをグループなしでフォームとしてページに追加する手順:
フォーム上の属性を動的コンポーネントを使用してグループ化するときは、グループに属する属性をフォーム上のある部分に配置し、どのグループにも属していない属性を別の部分に配置する必要があります。スイッチャ・コンポーネントのファセットを使用して、この2つを分離します。
スイッチャ・コンポーネントは、イテレータ・コンポーネントの子です。ただし、このイテレータは、AttributesModel
の属性にバインドされるのではなく、モデルのhierarchicalAttributes
にバインドされ、オブジェクトを自身の変数内に格納します。スイッチャのファセット内にある別のイテレータが、このhierarchicalAttributes
オブジェクトの中にあるディスクリプタにバインドされます。このイテレータから、動的コンポーネントの情報が取得されます。
始める前に:
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。「実行時のコンポーネントの決定について」を参照してください。
動的コンポーネントをグループ付きでフォームとしてページに追加する手順:
ADF Facesでは、表の列をイテレータの中にラップして、動的コンポーネントを表の中で使用することができます。イテレータは、属性とその定義をAttributeModelから取得します。次に、表の列の情報を使用して、列のヘッダー・テキストが決定されます。2つのファセットを持つスイッチャ・コンポーネントを使用して、属性をグループ化することもできます。
動的コンポーネントを表の中で使用するときは、表の列をイテレータの中にラップする必要があります。このイテレータがAttributesModel
にアクセスして属性とその定義を取得します。この情報を使用して、列のヘッダー・テキストが決定されます。動的コンポーネントは、イテレータによってスタンプ・アウトされた属性インスタンスごとに情報を取得して、どのコンポーネントを使用するか、およびどのように構成するかを特定すると同時に、表の変数を使用して、どのデータを表示するかを決定します。
表内の属性をグループ化する場合は、ファセットを2つ持つスイッチャ・コンポーネントも使用する必要があります。ファセットの1つは、グループを対応する属性とともに表示するものであり、もう1つのファセットはどのグループにも属していない属性を表示します。
動的コンポーネントを表の中で使用するには、表コンポーネントをデータにバインドします。column
コンポーネントのかわりに、イテレータが表の動的な子となり、このイテレータはAttributesModel
のattributes
プロパティにバインドされます。列は、このイテレータの子です。動的コンポーネントは、列の子です。
始める前に:
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。「実行時のコンポーネントの決定について」を参照してください。
動的コンポーネントをグループなしで表としてページに追加する手順:
次の例に、動的表用に作成された宣言的コードを示します。
<af:table value="#{TestDynCompBean}" var="row" rowBandingInterval="0" id="t1"> <af:iterator value="#{TestDynCompBean.attributesModel.attributes}" var="column" id="i1"> <af:column headerText="#{column.label}" id="c1"> <af:dynamicComponent attributeModel="#{column}" value="#{row[column.name]}" id="dc1"/> </af:column> </af:iterator> </af:table>
表の中の属性を動的コンポーネントを使用してグループ化するときは、グループが親列として表示されます。図21-2に示すEmployee
オブジェクトの特定の属性は、「Employee Personal」グループおよび「Department Info」グループに属しています。
図21-2 グループを使用する動的コンポーネントを持つ表
スイッチャ・コンポーネントを使用して、グループに属している属性とそうでない属性とを分離します。ただし、このメイン・イテレータは、AttributesModel
の属性にバインドされるのではなく、モデルのhierarchicalAttributes
にバインドされ、オブジェクトを自身の変数内に格納します。スイッチャのファセット内にある別のイテレータが、このhierarchicalAttributes
オブジェクトの中にあるディスクリプタにバインドされます。このイテレータから動的コンポーネントの情報が取得されて、コンポーネントに属性のグループを表示できるようになります。
AttributeModel
のhierarchicalAttributes
によって、AttributeModel
のルート・レベルの属性が定義されます。ルート・レベルの属性が通常の属性である場合、つまりその属性のタイプがATTRIBUTEである場合は、この属性はどのグループにも属しておらず、表ではその属性に対して1つの列がレンダリングされます。ルート・レベルの属性がグループ化された属性である場合、つまり属性のタイプがGROUPである場合は、このグループに属している通常の属性のリストが存在します。ファセット内のイテレータは、このグループを反復処理し、そのグループの中の各属性は列としてスタンプされます。たとえば、「Employee Personal」はGROUPタイプの属性であり、この中には通常の属性が3つあります。「Employee Number」、「Name」および「Salary」です(図21-2を参照)。
始める前に:
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。「実行時のコンポーネントの決定について」を参照してください。
動的コンポーネントをグループ付きで表としてページに追加する手順:
次の例に、グループを使用した動的表用に作成された宣言的コードを示します。
<af:table value="#{TestDynCompBean}" var="row" rowBandingInterval="0" id="t2"> <af:iterator value="#{TestDynCompBean.attributesModel.heirarchicalAttributes}" var="column" id="i2"> <af:column headerText="#{column.label}" id="c2"> <af:switcher defaultFacet="ATTRIBUTE" facetName="#{column.descriptorType}" id="s1"> <f:facet name="GROUP"> <af:iterator value="#{column.descriptors}" var="nestedCol" id="i3"> <af:column headerText="#{nestedCol.label}" id="c3"> <af:dynamicComponent attributeModel="#{nestedCol}" value="#{row[nestedCol.name]}" id="dc2"/> </af:column> </af:iterator> </f:facet> <f:facet name="ATTRIBUTE"> <af:dynamicComponent attributeModel="#{column}" value="#{row[column.name]}" id="dc3"/> </f:facet> </af:switcher> </af:column> </af:iterator> </af:table>
ADF Facesでは、ユーザーが動的コンポーネントに発行したデータを変換して検証することができます。アプリケーションの作成中に変換および検証する属性を指定するには、その動的コンポーネントにコンバータまたはバリデータのタグを追加する必要があります。
変換および検証を動的コンポーネントに追加するには、必要なコンバータまたはバリデータのタグを追加し、どの属性を検証または変換するかを指定します。enabled
属性のかわりに、動的コンポーネントではdisabled
属性が使用されます。
始める前に:
動的コンポーネントによって表示されるものがどのように決定されるかを理解しておくと役立ちます。「実行時のコンポーネントの決定について」を参照してください。
バリデータまたはコンバータを動的コンポーネントとともに使用する手順:
ADF Facesでは、動的フォームの前後に静的コンポーネント配置できます。フォーム内で動的コンポーネントと静的コンポーネントを使用して、複雑なフォームを作成することもできます。
動的フォームを作成する場合は、基本的に、動的にレンダリングされるコンポーネントのブロックを作成します。静的コンポーネントをこのコンポーネントのブロックの前または後に配置できますが、静的コンポーネントをそのブロックの中に配置することはできません。
このような制約はありますが、多数の動的および静的のコンポーネントを使用して複雑なフォームを作成できます。また、静的コンポーネントを、詳細なレベルの動的コンポーネントどうしの間に配置することもできます。
たとえば、フォームに名前と住所の情報を、英語と日本語の両方で表示する必要があるとします。この例では、日本語の情報は動的コンポーネントを使用して表示し、英語の情報は静的コンポーネントで表示するとします。図21-3に、フィールドの配置の例を示します。動的な日本語コンテンツを、静的コンテンツの後に表示しています。
次の例に、このフォームを作成する方法の例を示します。静的なinputText
コンポーネントと動的コンポーネントを使用して、NameグループおよびAddressグループの属性にアクセスします。
<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に示すように交互に表示するとします。
この場合は、動的コンポーネントの中でグループを使用するかわりに、必要な属性のみ(つまり、全部の属性ではありません)にアクセスします(次の例を参照)。
<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>