| Oracle® Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド 11gリリース1 (11.1.1.7.0) B52029-07 |
|
![]() 前 |
![]() 次 |
この章では、ADF Facesクライアント側アーキテクチャの主な機能について説明します。
この章では、次の項目について説明します。
ADF Facesリッチ・クライアント・フレームワーク(RCF)には、AJAXタイプの機能をWebアプリケーションに作成するために必要な機能が多く用意されており、すべてフレームワークに組み込まれています。RCFの基本は、クライアント側コンポーネント・モデルにあまり移入されないことです。クライアント・コンポーネントは、必要な場合にのみ存在しますが、これは、clientListenerハンドラが登録されている場合、あるいはページ開発者がクライアント側のコンポーネントと対話する必要があり、クライアント・コンポーネントが使用できるように構成してある場合のいずれかです。
クライアント・コンポーネントが存在する主な理由は、フレームワークおよび開発者に対するAPI規定を提供することです。クライアント側コンポーネントは、イベント処理がサポートされる簡単なプロパティ・コンテナとみなすことができます。クライアント・コンポーネントは、状態を格納し、APIを提供するためにのみ存在するため、Document Object Model(DOM)と直接対話しません。DOMとのすべての対話は、ピアと呼ばれる媒介を使用して行われます。フレームワークの内部動作の大部分は、意識する必要がありません。JDeveloperとADF Facesを組み合せて使用すると、アーキテクチャ上の機能の多くを宣言して使用でき、コードを作成する必要がありません。
たとえば、RCFでは、各サーバー側コンポーネントに対応するクライアント・コンポーネントをすべて作成するわけではないため、クライアント版のコンポーネント・インスタンスが必要な場合もあります。3.4項「クライアント側コンポーネントのインスタンス化」に、これを宣言的に行う方法が説明されています。JDeveloperのプロパティ・インスペクタを使用して、3.9項「レンダリングおよび可視性の理解」で説明されている、コンポーネントをレンダリングするかどうか、あるいは非表示にするかどうかを決めるプロパティを設定します。
その他の機能では、ADF Faces JavaScript APIの使用が必要になる場合があります。たとえば、3.5項「ページでのクライアント・コンポーネントの検索」では、APIを使用して特定のクライアント側コンポーネントを検索する方法が説明されており、3.7項「クライアントでのコンポーネント・プロパティへのアクセス」には、特定のプロパティへのアクセス方法が記載されています。
次のRCF機能はより複雑です。このため、個別の章が使用されています。
ライフサイクルへのADF Facesの追加機能: ADF FacesフレームワークでJSFライフサイクルを拡張し、クライアント側の値のライフサイクルなどの追加機能を提供します。詳細は、第4章「ADF FacesでのJSFライフサイクルの使用」を参照してください。
イベント処理: ADF FacesはJSFイベント処理手法に準拠しています。また、RCFにはAJAXベースのリッチ・ポストバック(部分ページ・レンダリングと呼ばれる)とクライアント側イベント・モデルが用意されています。詳細は、第5章「イベントの処理」を参照してください。
変換および検証: ADF Faces入力コンポーネントには、ユーザー入力の変換および検証の両方の機能が組み込まれています。独自のカスタム・コンバータとバリデータを作成することもできます。詳細は、第6章「入力の検証および変換」を参照してください。
部分ページ・レンダリング: 部分ページ・レンダリング(PPR)を使用すると、ページ内の小さい領域を、ページ全体を再描画せずにリフレッシュできます。ADF Facesコンポーネントの多くにPPR機能が組み込まれています。また、あるコンポーネントに対するアクションによって別のコンポーネントが再レンダリングされるようPPRを宣言的に構成することもできます。詳細は、第7章「部分ページ・コンテンツの再レンダリング」を参照してください。
ジオメトリ管理: ADF Facesには、レイアウト・コンポーネントが多く用意されており、この多くでコンテンツを使用可能な領域いっぱいに自動的に拡大することでジオメトリ管理をサポートします。詳細は、第8章「Webページ上のコンテンツの編成」を参照してください。
メッセージおよびヘルプ: RCFには、入力コンポーネントのツールチップ、メッセージおよびヘルプを表示する機能と、アプリケーションのグローバル・メッセージを表示する機能が用意されています。ヘルプ・フレームワークによって、アプリケーション全体で再利用可能なメッセージを作成できます。Javaクラス、マネージドBean、XLIFFファイルまたは標準プロパティ・ファイルを使用してヘルプ・プロバイダを作成したり、HTMLベースの外部ヘルプ・システムにリンクできます。詳細は、第17章「ヒント、メッセージおよびヘルプの表示」を参照してください。
階層型メニュー・モデル: ADF Facesには、階層式のページをナビゲートするためのタブやブレッドクラムなどのアイテムをレンダリングするナビゲーション・コンポーネントが用意されています。RCFで、メタデータ・ファイルとともに使用し、各ページに適切な数の階層レベルを生成するためのすべての情報と、各レベルに属するナビゲーション・アイテムを含むXMLベースのメニュー・モデルが提供されます。詳細は、第18章「ナビゲーション・コンポーネントの使用」を参照してください。
再利用可能なコンポーネント: RCFには、アプリケーションの複数のページで使用できる再利用可能な3つのビルディング・ブロックが用意されています(ページ・フラグメントでは、ページの一部(住所入力フォームなど)を作成できます。ページ・テンプレートでは、アプリケーション全体で一貫したルック・アンド・フィールが得られ、更新可能で、テンプレートを使用するすべてのページに変更が自動的に伝播されます。宣言コンポーネントは、開発者が再利用できるコンポジット・コンポーネントで、アプリケーション全体で動作に矛盾がないようにします)。詳細は、第19章「フラグメント、ページ、テンプレート、コンポーネントの作成および再利用」を参照してください。
スキンの適用: RCFでは、ADF Facesコンポーネントで外観の変更に使用するスキンを作成することで、独自のルック・アンド・フィールを作成できます。詳細は、第20章「スタイルおよびスキンを使用した外観のカスタマイズ」を参照してください。
国際化およびローカライズ: 異なるロケールを使用するようJSFページまたはアプリケーションを構成し、ユーザーのブラウザの言語設定に基づいて適切な言語を表示できます。詳細は、第21章「ページの国際化およびローカライズ」を参照してください。
アクセシビリティ: ADF Facesコンポーネントには、ユーザー・エージェント(スクリーン・リーダー、拡大鏡などのビジュアル・メディア以外にレンダリングするWebブラウザ)に対するアクセシビリティ・サポートが組み込まれています。アクセシビリティ・サポートには、ユーザーがキーボードのみを使用してコンポーネントやリンクにアクセスできるアクセス・キー、アクセシブルHTMLマークアップを使用したアクセシブルなイメージ、表、フレーム、フォーム、エラー・メッセージおよびポップアップ・ダイアログの作成手順を提供する監査ルールも含まれます。詳細は、第22章「アクセス可能なADF Facesページの開発」を参照してください。
ユーザー駆動型パーソナライズ: 多くのADF Facesコンポーネント(panelSplitterなど)で、ユーザーは実行時にコンポーネントの表示を変更できます。デフォルトでは、これらの変更はページ・リクエストの間有効です。ただし、変更がユーザーのセッションの間永続するようアプリケーションを構成できます。詳細は、第33章「JSFページでのユーザー・カスタマイズの許可」を参照してください。
ドラッグ・アンド・ドロップ機能: RCFで、ユーザーは、ある場所から別の場所へデータを移動(切り取って貼付け)、コピー(コピーして貼付け)およびリンク(コピーしてリンクとして貼付け)できます。ドロップが完了すると、ドロップの受入れ先コンポーネントで部分ページ・レンダリングを使用して再レンダリングが行われます。詳細は、第34章「ドラッグ・アンド・ドロップ機能の追加」を参照してください。
この章の以降の項では、クライアント側フレームワークの使用に焦点を当てます。
従来のJSFアプリケーションでは、クライアントでイベントを処理する場合、DOMレベルのイベントをリスニングする必要があります。ただし、これらの実装は移植可能な形式で配信されません。ADF Facesのクライアント側イベント・モデルはJSFイベント・モデルと似ていますが、クライアントで実装されます。クライアント側イベント・モデルはDOMの要約で、コンポーネントレベルのイベント・モデルとライフサイクルが提供され、サーバーから独立して実行されます。このため、ボタンのclickイベントをリスニングする必要がありません。かわりに、キーまたはマウスのイベントで発生するAdfActionEventイベントをリスニングできます。
クライアントによって送信されるイベントはすべてAdfBaseEventクラスのサブクラスです。各クライアント・イベントには、イベントをトリガーしたコンポーネントであるソースがあります。イベントには、イベントをリスニングするリスナーを判断するタイプ(actionまたはdialogなど)もあります。クライアント・リスナーは、af:clientListenerタグを使用してコンポーネントに登録します。
たとえば、クリックされると「Hello World」アラートを表示するボタンがあるとします。例3-1に示すように、まず、イベント・ハンドラを起動するリスナーをボタンに登録します。
例3-1 クライアント・リスナーの登録
<af:commandButton text="Say Hello"> <af:clientListener method="sayHello" type="action"/> </af:commandButton>
|
ヒント: ボタンにクライアント・リスナーが登録されているため、フレームワークで、クライアント版のコンポーネントが自動的に作成されます。 |
次に、例3-2に示すようなハンドラをJavaScript関数に作成します。
クライアント版のコンポーネントがあるため、ボタンがクリックされると、AdfActionクライアント・イベントが起動されます。AdfActionイベントをリスニングするようclientListenerタグが構成されているため、sayHello関数が実行されます。クライアント側イベントの詳細は、5.3項「ADF Facesクライアント・イベントに対するJavaScriptの使用」を参照してください。
JavaScriptをページにインラインで直接追加することも、JavaScriptライブラリをページにインポートすることもできます。ライブラリをインポートすると、ページのコンテンツ・サイズが小さくなり、ライブラリをページ間で共有して、ブラウザでキャッシュできます。可能な場合はJavaScriptライブラリをインポートしてください。インラインのJavaScriptは、小規模でページ固有のスクリプトが必要な場合にのみ使用します。
|
パフォーマンスのヒント: 必要なページにのみJavaScriptを含めることで、パフォーマンスが向上しますが、これは、テンプレートにJavaScriptが含まれている場合のように、JavaScriptの不要なページでJavaScriptをロードする必要がないためです。ただし、ほとんどのページで同じJavaScriptコードが使用されている場合、テンプレートにライブラリをインポートするスクリプトまたはタグを含めることを検討してください。 ただし、JavaScriptコード・ライブラリが非常に大きくなった場合、ライブラリを内容に応じて分割し、(テンプレートではなく)ページで必要な部分のみを含めることに注意してください。この方法で、ブラウザ・キャッシュが使用され、ページのHTMLコンテンツが小さくなるため、パフォーマンスが向上します。 |
インラインのJavaScriptは、JSFアプリケーションと同様に作成および使用します。JavaScriptがページに含まれる場合、clientListenerタグを使用して起動します。
インラインのJavaScriptを使用する手順:
例3-3に太字で示すコードを追加して、MyFaces Trinidadタグ・ライブラリをページのルート要素に追加します。
ページにJavaScriptを作成します。
たとえば、例3-2に示すsayHello関数は、例3-4のようにJSFページに含めることができます。
|
注意: ページまたはテンプレートに |
構造ウィンドウで、JavaScriptを起動するコンポーネントを右クリックし、「<コンポーネントの中に挿入」→「ADF Facesコア」→「クライアント・リスナー」を選択します。
「クライアント・リスナーの挿入」ダイアログで「メソッド」フィールドにJavaScript関数の名前を入力します。タイプ・フィールドで、関数を起動するイベント・タイプを選択します。
af:resourceタグを使用して、ページからJavaScriptライブラリにアクセスします。このタグは、documentタグのmetaContainerファセットの内部に含める必要があります。
ページからJavaScriptライブラリにアクセスする手順:
documentタグの下に、例3-5に太字で示すコードを追加し、JavaScriptライブラリが含まれるディレクトリへの相対パスに/mySourceDirectoryを置き換えます。
構造ウィンドウで、JavaScriptを起動するコンポーネントを右クリックし、「<コンポーネントの中に挿入」→「ADF Facesコア」→「クライアント・リスナー」を選択します。
「クライアント・リスナーの挿入」ダイアログで「メソッド」フィールドに関数の完全修飾名を入力します。たとえば、sayHello関数がMyScriptsライブラリにある場合、MyScripts.sayHelloと入力します。タイプ・フィールドで、関数を起動するイベント・タイプを選択します。
JavaScriptでクライアントにアクセスする必要がある場合、リスナーのコンテキストで行われ、イベントのソース・コンポーネントにアクセスする必要がある場合がしばしばあります。getSource()メソッドを使用してクライアント・コンポーネントを取得します。例3-6に、名前を表示するためにソース・クライアント・コンポーネントにアクセスするsayHello関数を示します。
例3-6 クライアント・イベント・ソースへのアクセス
function sayHello(actionEvent)
{
var component=actionEvent.getSource();
//Get the ID for the component
var id=component.getId
alert("Hello from "+id);
}
クライアント・イベント・ソースへアクセスの詳細は、5.3項「ADF Facesクライアント・イベントに対するJavaScriptの使用」を参照してください。クライアント側プロパティへのアクセスの詳細は、3.7項「クライアントでのコンポーネント・プロパティへのアクセス」を参照してください。実行時のクライアント・イベントの処理の詳細は、5.3.6項「実行時の処理: クライアント側イベントの機能の仕方」を参照してください。
RCFでは、どのコンポーネントが、対応するクライアント側コンポーネント・インスタンスをデフォルトで持つかについて保証されません。通常、clientListenerハンドラを登録して、クライアント側コンポーネントと対話します。登録されているclientListenerハンドラがコンポーネントにある場合、コンポーネントはクライアント側表現を自動的に持ちます。クライアントの別のコンポーネントにアクセスする必要がある場合、clientComponent属性をtrueに設定して、そのコンポーネントがクライアントで使用できるよう明示的に構成します。
|
パフォーマンスのヒント: クライアントのコンポーネントとプログラムで対話する場合にのみ |
clientComponent属性をtrueに設定すると、コンポーネントのAdfUIComponentクラスのインスタンスがフレームワークで作成されます。このクラスでは、クライアント側で使用できるAPIが提供され、基本的なプロパティ・アクセッサ・メソッド(getProperty()、setProperty()など)、イベント・リスナーの登録およびイベント配信関連のAPIが提供されます。フレームワークには、プロパティ固有のアクセッサ・メソッド(getText()、setText()など)を公開するレンダラ固有のサブクラス(AdfRichOutputTextなど)も用意されています。これらのアクセッサ・メソッドは、AdfUIComponentクラスのgetProperty()およびsetProperty()メソッドをラップするのみのラッパーで、コーディングが簡便になるよう用意されています。
たとえば、sayHello関数から値(表示するテキスト)を取得するoutputTextコンポーネントがページにあるとします。この関数は、値を設定するためにoutputTextコンポーネントにアクセスできる必要があります。これが機能するには、クライアント側バージョンのoutputTextコンポーネントがある必要があります。例3-7に、JSFページ・コードを示します。outputTextコンポーネントにID値があり、clientComponent属性がtrueに設定されていることに注意してください。また、値はJavaScriptで設定されるため、例には値がないことにも注意してください。
例3-7 コンポーネントの追加
<af:commandButton text="Say Hello"> <af:clientListener method="sayHello" type="action"/> </af:commandButton> <af:outputText id="greeting" value="" clientComponent="true">
outputTextにクライアント側表現があるため、JavaScriptでこれを見つけて使用できます。
イベントのソースではないクライアント・コンポーネントを検索する必要がある場合、AdfUIComponent.findComponent(expr)メソッドを使用できます。このメソッドはJSFのUIComponent.findComponent()メソッドと似ており、指定した検索式に合致するIDを使用してUIComponentオブジェクトを検索して返します。AdfUIComponent.findComponent(expr)メソッドは、サーバーではなくクライアントでのみ機能します。
例3-8に、コンポーネントのIDを使用してoutputTextコンポーネントを検索するsayHello関数を示します。
例3-8 findComponent()を使用したクライアント・コンポーネントの検索
function sayHello(actionEvent)
{
var component=actionEvent.getSource();
//Find the client component for the "greeting" af:outputText
var greetingComponent=component.findComponent("greeting");
//Set the value for the outputText component
greetingComponent.setValue("Hello World")
}
コンポーネントの完全なIDはわかるが、AdfUIComponent.findComponent(expr)をコールするコンポーネント・インスタンスがない場合、AdfUIComponent.findComponent(expr)メソッドを使用するかわりに、AdfPage.PAGE.findComponentByAbsoluteId(absolute expr)メソッドを使用できます。AdfPage.PAGEは、ページのコンテキスト・オブジェクトへの静的参照を提供するグローバル・オブジェクトです。ただし、検索対象のコンポーネントがネーミング・コンテナ内にある場合、AdfUIComponent.findComponentを使用する必要があります。詳細は、3.5.1項「ネーミング・コンテナ内のコンポーネントの検索について」を参照してください。
|
注意: 似たような名前の |
見つける必要があるコンポーネントがネーミング・コンテナ(pageTemplate、subform、tableおよびtreeなど)であるコンポーネントにある場合は、AdfPage.PAGE.findComponentByAbsoluteId(absolute expr)メソッドを使用するかわりに、AdfUIComponent.findComponent(expr)メソッドを使用します。絶対式も相対式も使用できます。
|
ヒント: コンポーネントがネーミング・コンテナかどうかは、コンポーネント・タグのドキュメントを確認して判断できます。タグのドキュメントには、コンポーネントがネーミング・コンテナかどうかが示されています。 |
絶対式では、NamingContainer.SEPARATOR_CHAR文字を先頭とし、完全修飾されたJSFクライアントID(コンポーネントを含むNamingContainerコンポーネントのすべてのIDが先頭に付けられる)を使用し、次に例を示します。
":" + (namingContainersToJumpUp * ":") + some ending portion of the clientIdOfComponentToFind
たとえば、myTemplateテンプレートを使用するページで、IDがr1のリージョンに含まれ、IDがpc1のパネル・コレクション・コンポーネント内にあるIDがt1の表を検索するには、次を使用します。
:myTemplate:r1:pc1:t1
また、両方のコンポーネント(検索する側とされる側)が階層内のいずれかの場所で同じNamingContainerコンポーネントを共有する場合、相対パスを使用して、検索元のコンポーネントを基準とする検索を実行できます。相対パスには、たとえば、次のように複数のNamingContainer.SEPARATOR_CHAR文字を先頭に含めることができます。
":" + clientIdOfComponentToFind
前述の例で、検索元のコンポーネントが表と同じリージョンにある場合、次を使用できます。
::somePanelCollection:someTable
|
ヒント: ネーミング・コンテナはフォルダ、 |
絶対パスを使用するか相対パスを使用するかを決める際、次の点に注意します。
検索対象のコンポーネントが常に同じネーミング・コンテナ内あることがわかっている場合は、絶対パスを使用します。
検索元のコンポーネントと検索対象のコンポーネントの相対的位置が常に同じであることがわかっている場合は、相対パスを使用します。
クライアントにはgetChildren()関数もgetFacet()関数もありません。かわりに、すべての子コンポーネントとファセット(つまり、すべての子孫)にアクセスするAdfUIComponent.visitChildren()関数が用意されています。詳細は、ADF Faces JavaScriptのドキュメントを参照してください。
ADF Facesでは、イベントに関して現在のコンテキスト・ページ情報を返すJavaScript APIが用意されています。AdfPage.prototype.getViewId()関数では、現在表示されているビューの識別子を返します。このIDは、ページ全体のレンダリングまたは部分ページ・ナビゲーションのいずれかが発生すると設定されます。AdfPage.prototype.getComponentsByType(componentType)関数は、指定したコンポーネント・タイプに一致するコンポーネント・インスタンスの配列を返します。
たとえば、アプリケーションにタブ付きのページが含まれており、各タブが複数のリージョンで構成されているとします。各リージョンには、ネストされた他のリージョンも含めることができます。APIを使用すると、例3-9に示すように、ページ全体のviewIdと、ページで現在レンダリングされている各リージョンに表示されているフラグメントのviewIdsの組合せとなる文字列の識別子を返すことができます。
クライアント側のリージョン・コンポーネントのviewID propertyを取得するには、web.xmlファイルのパラメータを設定して、ユーザー・アクティビティ監視機能を有効にする必要があります。次に、現在のページを構成するviewIdsの文字列表現をビルドするJavaScriptコードを作成します。
コンテキスト識別子を決定する手順:
web.xmlファイルをダブルクリックします。
ソース・エディタで、oracle.adf.view.faces.context.ENABLE_ADF_EXECUTION_CONTEXT_PROVIDERをtrueに設定します。
このパラメータでは、ExecutionContextProviderサービス・プロバイダが有効であることがADF Facesに通知されます。このサービスでは、クライアント開始のリクエストのユーザー・アクティビティ情報を監視して集約します。
oracle.adf.view.rich.automation.ENABLEDをtrueに設定します。
このパラメータにより、すべてのコンポーネントでコンポーネントIDが設定されます。詳細は、A.2.3.11項「テストの自動化」を参照してください。
JavaScriptを作成し、コンテキスト識別子をビルドします(JavaScriptの追加の詳細は、3.3項「JavaScriptのページへの追加」を参照)。
例3-9に、リージョンの現在のビューIDを取得するのに使用するJavaScriptを示します。
例3-9 JavaScriptによるviewIdsの取得
/**
* Returns a String identifier comprising the page viewId and viewIds
* of the fragments displayed in each of the displayed regions
*/
TestLibrary.prototype.getCurrentPageInfo = function()
{
var pageIdentifier = null;
var page = AdfPage.PAGE;
if (page)
{
// get the viewId of the page
var viewId = page.getViewId();
// get all region components currently displayed on the page
var regionComponents = page.getComponentsByType("oracle.adf.RichRegion");
var regionViewIds = new Array();
for (var index = 0; index < regionComponents.length; index++)
{
var regionComp = regionComponents[index]);
if (regionComp)
{
regionViewIds.push(regionComp.getProperty("viewId"));
}
}
// construct page identifier
if (viewId != null && regionViewIds.length > 0)
contextId = viewId.concat(regionViewIds.toString());
}
return contextId;
}
コンポーネントの各組込みプロパティには、簡易アクセッサ・メソッドがコンポーネント・クラスに用意されています。たとえば、クライアント・コンポーネントでgetValue()メソッドをコールし、サーバーで使用されたのと同じ値を受け取ることができます。
|
注意: ブール・プロパティを含む、ADF Facesのすべてのクライアント・プロパティで |
定数もクラス・オブジェクトのプロパティ名に使用できます。たとえば、styleClassを使用するかわりにAdfRichDialog.STYLE_CLASS定数を使用できます。
|
注意: 文字列のコーディングは各起動時にオブジェクトの割当てが必要なため、JavaScriptでは定数を参照する方が効率的です。 |
コンポーネントのプロパティが変更されると、新しい状態が反映されるようコンポーネントのDOMが最終的に更新されますが、サーバーへのラウンドトリップがない場合もあります。この処理でのコンポーネントの役割は非常に限られており、新しいプロパティ値を格納し、ピアに変更を通知するのみです。ピアには、コンポーネントの新しい状態を反映するようDOMを更新するロジックが含まれています。
|
注意: すべてのプロパティの変更が、クライアント側のピアを使用して処理されるわけではありません。一部のプロパティ変更はサーバーに伝播され、PPRを使用してコンポーネントが再レンダリングされます。 |
1.2.2項「ADF Facesのアーキテクチャ上の機能」での説明のとおり、大半のプロパティ値はクライアントで設定されると、サーバーと自動的に同期されます(クライアントにまったく送信されない複雑なJavaオブジェクトもあります)。ただし、これとは異なる動作をするセキュア・プロパティと分離プロパティの2種類のプロパティもあります。
セキュア・プロパティは、クライアントでまったく設定できないプロパティです。たとえば、悪意のあるクライアントでJavaScriptを使用してcommandLinkコンポーネントのimmediateフラグがtrueに設定されるとします。この変更がサーバーに伝播された結果、サーバー側の検証が省略され、セキュリティ・ホールとなる可能性があります(immediateプロパティの使用の詳細は、4.2項「immediate属性の使用」を参照してください)。つまり、immediateプロパティはセキュア・プロパティです。
JavaScriptから他のセキュア・プロパティの設定を試みると失敗します。詳細は、3.7.2項「無効なプロパティを保護しない方法」を参照してください。表3-1に、クライアント・コンポーネントのセキュアなプロパティを示します。
表3-1 セキュアなクライアント・プロパティ
| コンポーネント | セキュアなプロパティ |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ADF Facesでは、保護されなくなるなるように、disabledプロパティを構成できます。これは、JavaScriptを使用してdisableボタンを有効にする必要がある場合に便利です。unsecureプロパティをtrueに設定すると、disabledプロパティ(およびdisabledプロパティのみ)が保護されなくなります。
分離プロパティは、クライアントで設定できるが、サーバーに伝播されないプロパティです。これらのプロパティには、サーバーでのライフサイクルに依存しないクライアントにライフサイクルがあります。たとえば、クライアント・フォーム入力コンポーネント(AdfRichInputTextなど)には、JavaのEditableValueHolderコンポーネントのようにsubmittedValueプロパティがあります。ただし、このプロパティの設定はサーバーに直接影響しません。この場合、標準のフォーム送信手法によって、送信された値のサーバーでの更新を処理します。
プロパティは、分離プロパティとセキュア・プロパティの両方にできます。実際には、このようなプロパティはクライアントで分離プロパティのように機能し、クライアントで設定できますが、サーバーに送信されません。しかし、サーバーでは、クライアントからの設定を受け付けないという点でセキュア・プロパティのように機能します。
RCFには、AdfUIComponentsetProperty()関数をコールするためのsetXYZ簡易関数が用意されています。setProperty()関数は次の引数をとります。
プロパティ名(必須)
新しい値(必須)
disabledプロパティが保護されないように設定するには、unsecuredプロパティを使用します。disabledプロパティが保護されないようにするコンポーネントのコードに、このプロパティと、disabledの値を手動で追加する必要があります。たとえば、disabledプロパティが保護されないようにするボタンのコードは、次のとおりです。
<af:commandButton text="commandButton 1" id="cb1" unsecure="disabled"/>
unsecure属性をdisabledに設定すると、悪意のあるJavaScriptによって、disabled属性が知らずに変更される可能性があります。たとえば、経費の承認ページがあり、そのページで、$200未満の請求書のみを特定のマネージャが承認できるようにします。このため、現在のユーザーが請求書の承認を許可されていない場合は、承認ボタンを無効にします。
unsecured属性をdisabledに設定していない場合、承認ボタンは、サーバーへのラウンドトリップが発生するまで無効のままになり、この場合は、現在のユーザーが経費を承認できるかどうかをロジックで決定します。しかし、経費がページにロードされる際に、ボタンを正しく表示する必要があるため、unsecure属性をdisabledに設定します。これで、クライアントでJavaScriptを使用して、ボタンを無効にするかどうかを決定できます。しかし、同じことは、どのJavaScript(制御できない悪意のあるJavaScriptも含む)でも可能です。
このような問題を回避するには、サーバへのラウンドトリップが実行されるのと同様に、同じロジックをアプリケーションで実行する必要があります。経費レポートの承認画面では、$200未満の金額をチェックするJavaScriptを使用できますが、承認ボタンのアクションがサーバでロジックを実行できるようにする必要があります。このロジックをサーバーに追加することにより、disabled属性を変更すべきでない場合は、変更されません。
同様に、実行時にアプリケーションを変更できるようにし、ユーザーがunsecureまたはdisabled属性(あるいはその両方)を潜在的に編集できるようにするには、サーバへのラウンドトリップが実行されるのと同様に、同じロジックをアプリケーションで実行する必要があります。
組込みプロパティ以外の情報をクライアントに送信する必要がある場合もあります。これは、ボーナス属性を使用して行えます。ボーナス属性は、clientAttributeタグを使用してコンポーネントに追加できる追加属性です。パフォーマンス上の理由から、クライアントに送信されるボーナス属性は、clientAttributeで指定されたもののみです。
clientAttributeタグで、サーバー側コンポーネントの属性マップに追加される名前と値のペアを指定します。clientAttributeタグを使用すると、サーバー側属性マップへの移入に加え、ボーナス属性のクライアントへの送信も行われます(クライアントではAdfUIComponent.getProperty("bonusAttributeName")メソッドを使用してアクセスできます)。
RCFで、属性値のクライアントへのマーシャリングが行われます。マーシャリング・レイヤーで、文字列、ブール、数値、日付、配列、マップなど、各オブジェクト型のマーシャリングがサポートされます。マーシャリングの詳細は、5.4.3項「データのマーシャリングとアンマーシャリングについて」を参照してください。
|
パフォーマンスのヒント: マーシャリングによる過度のオーバーヘッドを防ぐため、クライアント側ボーナス属性を多用しないでください。 |
|
注意:
|
コンポーネント・パレットを使用して、ボーナス属性をコンポーネントに追加できます。
ボーナス属性を作成する手順:
構造ウィンドウで、ボーナス属性を追加するコンポーネントを選択します。
コンポーネント・パレットの「操作」パネルから、「クライアント属性」をコンポーネントの子としてドラッグ・アンド・ドロップします。
プロパティ・インスペクタで「名前」と「値」属性を設定します。
クライアント側ボーナス属性は、サーバーからクライアントへ自動的に配信されますが、その逆は行われません。つまり、クライアントでのボーナス属性の変更または設定は、サーバーに反映されません。既知(ボーナス以外)の属性のみ、クライアントからサーバーへ同期がとられます。アプリケーションで定義されたデータをサーバーに送り返す必要がある場合、カスタム・イベントを作成します。詳細は、5.4項「クライアントからサーバーへのカスタム・イベントの送信」を参照してください。
すべてのADF Faces表示コンポーネントには、コンポーネントをページに表示してユーザーに見えるようにするかどうかに関係するrenderedとvisibleの2つの属性があります。
rendered属性のセマンティクは非常に厳密です。renderedがfalseに設定されている場合、サーバーへのラウンドトリップなしにコンポーネントをクライアントで表示することはできません。ページのコンテンツの動的な表示/非表示をサポートするために、RCFにはvisible属性が追加されています。falseに設定されている場合、コンポーネントのマークアップはクライアントで使用可能ですが、コンポーネントは表示されません。したがって、setVisible(true)またはsetVisible(false)メソッドをコールすると、JavaからのコールであろうとJavaScriptからのコールであろうと、コンポーネントがブラウザ内で表示または非表示になります(renderedがtrueに設定されている場合)。
|
パフォーマンスのヒント: JavaScriptなど、サーバーへのラウンドトリップなしに可視性を切り替える必要がある場合にのみ クライアントでのみ可視性を切り替える必要がない場合、かわりに |
例3-10に、2つのoutputTextコンポーネント(一度に1つのみレンダリングが表示)を示します。1つ目のoutputTextコンポーネントは、inputTextコンポーネントに値が入力されなかった場合にレンダリングされます。2つ目のoutputTextコンポーネントは、値が入力された場合にレンダリングされます。
例3-10 レンダリングされる/レンダリングされないコンポーネント
<af:panelGroupLayout layout="horizontal">
<af:inputText label="Input some text" id="input"
value="#{myBean.inputValue}"/>
<af:commandButton text="Enter"/>
</af:panelGroupLayout>
<af:panelGroupLayout layout="horizontal">
<af:outputLabel value="You entered:"/>
<af:outputText value="No text entered" id="output1"
rendered="#{myBean.inputValue==null}"/>
<af:outputText value="#{myBean.inputValue}"
rendered="#{myBean.inputValue !=null}"/>
</af:panelGroupLayout>
コンポーネントがクライアントでレンダリングされる場合、visibleプロパティを使用してコンポーネントをページに表示したり、非表示にできます。
例3-11に、例3-10と同じ機能を達成する方法を示しますが、この例では、visible属性を使用して表示するコンポーネントを決めます(rendered属性はデフォルトでtrueで、明示的に設定する必要はありません)。
例3-11 表示可能/表示不可能なコンポーネント
<af:panelGroupLayout layout="horizontal">
<af:inputText label="Input some text" id="input"
value="#{myBean.inputValue}"/>
<af:commandButton text="Enter"/>
</af:panelGroupLayout>
<af:panelGroupLayout layout="horizontal">
<af:outputLabel value="You entered:"/>
<af:outputText value="No text entered" id="output1"
visible="#{myBean.inputValue==null}"/>
<af:outputText value="#{myBean.inputValue}"
visible="#{myBean.inputValue !=null}"/>
</af:panelGroupLayout>
ただし、visible属性のかわりにrendered属性を使用することは、サーバー側でのパフォーマンスを向上させるため、JavaScriptで可視性を処理することもできます。
例3-12に、コンポーネントの可視性を処理するJavaScriptのページ・コードを示します。
例3-12 JavaScriptを使用した可視性の切替え
function showText()
{
var output1 = AdfUIComponent.findComponent("output1")
var output2 = AdfUIComponent.findComponent("output2")
var input = AdfUIComponent.findComponent("input")
if (input.getValue() == "")
{
output1.setVisible(true);
}
else
{
output2.setVisible(true)
}
}
コンポーネントのvisible属性を切り替えられる条件付きJavaScript関数を作成できます。
可視性を設定する手順:
可視性を切り替えるJavaScriptを作成します。例3-12に、値がない場合にoutputTextコンポーネントの可視性を有効にし、そうでない場合は別のoutputTextコンポーネントの可視性を有効にするスクリプトを示します。
JavaScript関数に必要なコンポーネントごとに、プロパティ・インスペクタで拡張セクションを開き、ClientComponent属性をtrueに設定します。これによって、JavaScriptで使用されるクライアント・コンポーネントが作成されます。
可視性を切り替えるコンポーネントのvisible属性をfalseに設定します。
例3-13に、JavaScriptを使用した可視性の切替えに使用されるページ・コード全体を示します。
例3-13 JavaScriptでの可視性の切替え
<f:view>
<af:resource>
function showText()
{
var output1 = AdfUIComponent.findComponent("output1")
var output2 = AdfUIComponent.findComponent("output2")
var input = AdfUIComponent.findComponent("input")
if (input.value == "")
{
output1.setVisible(true);
}
else
{
output2.setVisible(true)
}
}
</af:resource>
<af:document>
<af:form>
<af:panelGroupLayout layout="horizontal">
<af:inputText label="Input some text" id="input"
value="#{myBean.inputValue}" clientComponent="true"
immediate="true"/>
<af:commandButton text="Enter" clientComponent="true">
<af:clientListener method="showText" type="action"/>
</af:commandButton>
</af:panelGroupLayout>
<af:panelGroupLayout layout="horizontal">
<af:outputLabel value="You entered:" clientComponent="false"/>
<af:outputText value="No text entered" id="output1"
visible="false" clientComponent="true"/>
<af:outputText value="#{myBean.inputValue}" id="output2"
visible="false" clientComponent="true"/>
</af:panelGroupLayout>
</af:form>
</af:document>
</f:view>
コンポーネントの親のvisible属性がfalseに設定されている場合、visible属性がtrueに設定されている子コンポーネントにisVisible関数が実行されると、子が表示されていなくてもtrueが返されます。たとえば、outputTextコンポーネントを子として含むpanelGroupLayoutコンポーネントがあり、panelGroupLayoutコンポーネントのvisible属性がfalseに設定され、outputTextコンポーネントのvisible属性がデフォルトのまま(true)とします。クライアントでは、panelGroupLayoutコンポーネントもoutputTextコンポーネントも表示されませんが、isVisible関数がoutputTextコンポーネントに実行されると、trueが返されます。
このため、RCFにはisShowing()関数が用意されています。この関数は、コンポーネントのvisible属性がfalseに設定されている場合、またはコンポーネントの親のvisibleがfalseに設定されている場合、falseを返します。