Oracle® Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド 11gリリース1 (11.1.1.7.0) B52029-11 |
|
前 |
次 |
この章では、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関数に作成します。
クライアント版のコンポーネントがあるため、ボタンがクリックされると、Adf
Action
クライアント・イベントが起動されます。AdfAction
イベントをリスニングするようclientListener
タグが構成されているため、sayHello
関数が実行されます。クライアント側イベントの詳細は、5.3項「ADF Facesクライアント・イベントに対する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を呼び出すコンポーネントを右クリックし、「componentの中に挿入」→「ADF Faces」→「クライアント・リスナー」の順に選択します。
「クライアント・リスナーの挿入」ダイアログで「メソッド」フィールドにJavaScript関数の名前を入力します。タイプ・フィールドで、関数を起動するイベント・タイプを選択します。
af:resource
タグを使用して、ページからJavaScriptライブラリにアクセスします。このタグは、document
タグのmetaContainer
ファセットの内部に含める必要があります。
ページからJavaScriptライブラリにアクセスする手順:
document
タグの下に、例3-5に太字で示すコードを追加し、JavaScriptライブラリが含まれるディレクトリへの相対パスに/mySourceDirectory
を置き換えます。
「構造」ウィンドウで、JavaScriptを呼び出すコンポーネントを右クリックし、「componentの中に挿入」→「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.10項「テストの自動化」を参照してください。
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を使用してボタンを有効および無効にする必要がある場合に役立ちます。unsecure
プロパティをtrue
に設定すると、disabled
プロパティ(およびdisabled
プロパティのみ)が保護されなくなります。
分離プロパティは、クライアントで設定できるがサーバーに伝播することはできないプロパティです。これらのプロパティには、サーバーのライフサイクルに依存しないクライアント上のライフサイクルがあります。たとえば、クライアント・フォーム入力コンポーネント(AdfRichInputText
など)には、JavaのEditableValueHolder
コンポーネントのようにsubmittedValue
プロパティがあります。ただし、このプロパティの設定はサーバーに直接影響しません。この場合、標準のフォーム送信手法によって、送信された値のサーバーでの更新を処理します。
プロパティは、分離とセキュアの両方にすることができます。実際には、このようなプロパティはクライアント上で分離プロパティのように動作します。これらはクライアントで設定できますが、サーバーには送信されません。ただし、サーバーではセキュア・プロパティとして動作するため、クライアントがこれらを設定しようとすると拒否されます。
RCFには、AdfUIComponent
setProperty()
関数をコールするためのsetXYZ
簡易関数が用意されています。setProperty()
関数は次の引数をとります。
プロパティ名(必須)
新しい値(必須)
unsecured
プロパティを使用して、disabled
プロパティを非保護に設定します。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があっても、承認ボタンのアクションではサーバー上のロジックを実行する必要があります。サーバーにロジックを追加すると、無効な属性を変更してはならない場合に、それが変更されません。
同様に、アプリケーションを実行時に変更できるようにし、ユーザーが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
コンポーネントを示します。一度にその一方のみがレンダリングされます。最初の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
を返します。