6 イベントの処理
この章の内容は次のとおりです。
イベントおよびイベント処理について
ADF Facesは、サーバー側のアクションおよび値変更イベントをサポートし、クライアント側のアクションおよび値変更イベントも起動できます。ADF Facesには、一連のイベント・タイプおよびイベント・ルート・コンポーネントが用意されています。
従来のJSFアプリケーションでは、イベント処理は通常サーバーで行われます。JSFのイベント処理はJavaBeansイベント・モデルをベースにしており、JSFアプリケーションでイベント・クラスおよびイベント・リスナー・インタフェースを使用して、コンポーネントで生成されたイベントが処理されます。
アプリケーションでのイベントの例には、ボタンまたはリンクのクリック、メニューまたはリストからの項目の選択、入力フィールドの値の変更などがあります。ボタンのクリックなどのユーザー・アクティビティが発生すると、コンポーネントは、イベントに関する情報を格納し、イベントを生成したコンポーネントを識別するイベント・オブジェクトを作成します。イベントはイベント・キューにも追加されます。JSFライフサイクル内の適切な時期に、JSFは、コンポーネントに対して、対応する登録済リスナーにイベントをブロードキャストするように指示し、リスナーは、イベントを処理するリスナー・メソッドを起動します。リスナー・メソッドによって、ユーザー・インタフェースの変更がトリガーされる場合、またはバックエンド・アプリケーション・コードが起動される場合(あるいはその両方)があります。
標準JSFコンポーネントと同様に、コンポーネントがアクティブになると、ADF FacesコンポーネントでActionEvent
イベントが配信され、コンポーネントのローカル値が変更されると、ADF Facesの入力および選択コンポーネントでValueChangeEvent
イベントが配信されます。
たとえば、File Explorerアプリケーションでは、commandMenuItem
コンポーネントを使用してユーザーがファイルまたはフォルダを新たに作成できるサブメニューが「ファイル」メニューに含まれます。ユーザーが「フォルダ」commandMenuItem
をクリックすると、ActionEvent
イベントが起動されます。コンポーネントのactionListener
属性の値として設定されているEL式がheaderManager
マネージドBeanのcreateNewDirectory
メソッドと解決されるため、このメソッドが起動されてディレクトリが新たに作成されます。
注意:
組込みイベント機能を持つADF Facesコンポーネントはform
タグに含める必要があります。
ADF Facesは標準JSFイベント処理手法に準拠していますが、次の2つの主要な方法を提供することでイベント処理機能を向上させています。
-
AJAXベースの機能(部分ページ・レンダリング)
-
クライアント側イベント・モデル
イベントおよび部分ページ・レンダリング
標準JSFイベントとは異なり、ADF FacesイベントではAJAXスタイルの部分ポストバックがサポートされ、部分ページ・レンダリング(PPR)が行えます。フル・ページ・レンダリングのかわりに、ADF Facesのイベントおよびコンポーネントでは、リクエスト時にページの一部のみがリフレッシュされる部分ページ・レンダリングがトリガーされます。ライフサイクルはその部分でのみ実行されます。
特定のコンポーネントはイベント・ルート・コンポーネントとみなされます。イベント・ルート・コンポーネントによってページでの境界が決まるため、その境界内のコンポーネントにのみライフサイクルを実行できます(ライフサイクルのこの機能の詳細は、「最適化されたライフサイクルの使用」を参照)。イベント・ルート内でイベントが発生した場合、ページでは、ルートの子であるコンポーネントのみリフレッシュされます。
イベント・ルート・コンポーネントの例はポップアップです。ポップアップ内でイベントが発生した場合は、ポップアップとその子のみレンダリングされ、ページ全体はレンダリングされません。その他の例は、表の周囲にあるpanelCollection
コンポーネントで、特にツールバーを表示します。ツールバー上のボタンからトリガーされたアクション・イベントによって、ライフサイクルがpanelCollection
コンポーネントの子コンポーネントでのみ実行されます。
イベント・ルート・コンポーネントとみなされるコンポーネントは、次のとおりです。
-
popup
-
region
-
panelCollection
-
calendar
-
editableValueHolder
コンポーネント(inputText
など)
また、特定のイベントは、特定のコンポーネントをイベント・ルート・コンポーネントとして指定します。たとえば、showDetail
コンポーネントを展開または縮小する(「コンテンツの動的な表示および非表示」を参照)と送信される表示イベントは、showDetail
コンポーネントがルートであることを示します。ライフサイクルはshowDetail
コンポーネント(および子コンポーネントまたはこれをトリガーとするその他のコンポーネント)でのみ実行され、展開または縮小時にこのコンポーネントのみがレンダリングされます。コンポーネントとその関連イベントの詳細は、「イベントとイベントのルート・コンポーネント」を参照してください。
ヒント
イベント・ルートを処理したときにイベント・ルートの外部にあるコンポーネントを処理する必要がある場合は、どのコンポーネントをサポートするのか、それらをライフサイクル内で実行すべきか、または単にレンダリングすべきかをプログラムにより決定できます。「部分ページ・コンテンツの再レンダリング」を参照してください。
イベントとイベントのルート・コンポーネント
表6-1に、ADF Facesでのすべてのイベント・タイプと、ソース・コンポーネントがイベント・ルートかどうかを示します。
表6-1 イベントとイベントのルート・コンポーネント
イベント・タイプ | コンポーネントのトリガー先 | イベント・ルートか |
---|---|---|
|
すべてのコマンド・コンポーネント |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
すべてのコマンド・コンポーネント |
NA |
|
|
|
|
|
NA |
|
|
|
|
|
NA |
|
|
NA |
|
|
NA |
|
すべてのコンポーネント |
NA |
|
|
|
|
|
|
|
|
NA |
|
|
NA |
|
すべてのコマンド・コンポーネント |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
すべての入力および選択コンポーネント( |
|
クライアント側イベント・モデル
サーバー側のアクションおよび値変更イベントの他に、ADF Facesコンポーネントでは、クライアント側のアクションおよび値変更イベント、その他のサーバーおよびクライアント・イベントが起動されます。サーバー・コンポーネントとクライアント・コンポーネントの両方で生成されるイベント(選択イベントなど)も、サーバー・コンポーネントでのみ生成されるイベント(起動イベントなど)も、クライアント・コンポーネントでのみ生成されるイベント(ロード・イベントなど)もあります。
デフォルトでは、ほとんどのクライアント・イベントはサーバーに伝播されます。コンポーネント状態に対する変更は、サーバーに自動的に同期されて状態の一貫性が確保され、必要に応じてイベントがサーバーに配信されてさらに処理されます。ただし、伝播されないようにイベントを構成することもできます。
また、サーバー側Javaコンポーネントにクライアント側イベント・リスナーを登録すると、ADF FacesフレームワークでJavaScriptコンポーネントが必要であるとみなされ、クライアント側コンポーネントが作成されます。
クライアント側JavaScriptイベントのソースはいくつかあります。DOMイベントやプロパティ変更イベントから自動的に導出されることもあれば、他のイベントの処理時に手動で作成することもできます。
ADF Facesサーバー・イベントの使用
ADF Facesは、サーバー側のアクションおよび値変更イベントをサポートしています。そのイベントを処理するには、使用可能な各種のサーバー側イベントと、そのイベントをトリガーするコンポーネントについて理解する必要があります。
ADF Facesには、多数のサーバー側イベントが用意されています。表6-2に、サーバーのADF Facesコンポーネントで生成されるイベントと、これをトリガーするコンポーネントを示します。
表6-2 ADF Facesサーバー・イベント
イベント | トリガー元コンポーネント |
---|---|
|
すべてのコマンド・コンポーネント。「共有コンポーネントでの作業」を参照してください。 |
|
イベントに基づくコンポーネントの更新に使用されます。『Application Development FrameworkによるFusion Webアプリケーションの開発』で、アクティブ・データ・サービスの使用方法に関する項を参照してください。 |
|
すべての入力および選択コンポーネント( |
|
Calendarコンポーネント。「Calendarコンポーネントの使用方法」を参照してください。 |
|
|
|
|
|
|
|
|
|
|
|
ドラッグ・アンド・ドロップをサポートするコンポーネント。「ドラッグ・アンド・ドロップ機能の追加」を参照してください。 |
|
treeおよび |
|
|
|
すべてのコマンド・コンポーネント。「共有コンポーネントでの作業」を参照してください。 |
|
|
|
|
|
|
|
ポップアップ・コンポーネント。「ポップアップ・ダイアログ、メニューおよびウィンドウの使用方法」を参照してください。 |
|
|
|
|
|
|
|
すべてのコマンド・コンポーネント。「共有コンポーネントでの作業」を参照してください。 |
|
|
|
ポップアップ・コンポーネント。「ポップアップ・ダイアログ、メニューおよびウィンドウの使用方法」を参照してください。 |
|
treeおよび |
|
|
|
|
|
すべての入力および選択コンポーネント( |
|
ウィンドウの |
|
新しい場所にナビゲートするために現在のウィンドウがアンロードされたときに配信されます。Java APIリファレンスfor Oracle ADF Facesを参照してください。 |
* このフォーカス・イベントは、特定のサブツリーがフォーカスされると生成されます。クライアント側のキーボード・フォーカス・イベントとは異なります。
** LoadEvent
イベントは、初期ページが表示された後に起動されます(データ・ストリーミングの結果は後で届くことがあります)。
サーバー側イベントの処理方法
すべてのサーバー・イベントには、関連付けられたコンポーネントに対するイベント・リスナーがあります。そのイベントを処理するハンドラを作成し、そのハンドラ・コードをコンポーネントのリスナーと関連付ける必要があります。
たとえば、File Explorerアプリケーションの場合、ユーザーが表の行を選択すると選択イベントが起動されます。表のselectionListener
属性は、TableContentView.java
マネージドBeanのtableSelectFileItem
ハンドラ・メソッドにバインドされているため、このメソッドがイベントに対応して起動されます。
始める前に:
サーバー側イベントに関する知識が役立つ場合があります。「ADF Facesサーバー・イベントの使用」を参照してください。
サーバー側イベントを処理する手順:
ADF Facesクライアント・イベントに対するJavaScriptの使用
ADF Facesは、クライアント側のアクションおよび値変更イベントを起動できます。クライアント側イベントを処理するには、使用可能な各種のイベントと、そのイベントをトリガーするコンポーネントについて理解する必要があります。クライアント側イベントを使用するには、まず、イベントを処理するJavaScriptを作成する必要があります。
ほとんどのコンポーネントは、クライアント側イベントに対しても動作できます。クライアント上でイベントを処理すると、サーバーとのラウンドトリップが節約されます。クライアント側イベントを使用する場合は、マネージドBeanにイベント・ハンドラ・コードを含めるかわりに、コール元のページまたはJavaScriptライブラリに含めることのできるJavaScriptを使用します。
デフォルトでは、クライアント・イベントはクライアントでのみ処理されます。ただし、ボタンがクリックされたことを示すAdfActionEvent
イベントのようにサーバーに配信されるイベント・タイプもあります。コンポーネントの状態に応じてサーバーに配信されるイベントもあります。たとえば、AdfValueChangeEvent
イベントは、autoSubmit
属性がtrue
に設定されている場合サーバーに配信されます。追加処理が不要な場合は、イベントのサーバーへの配信を取り消すことができます。ただし、取り消すことができないクライアント・イベントもあります。たとえば、popupOpened
イベント・タイプは、ポップアップ・ウィンドウが開くと配信されるため、このイベントのサーバーへの配信は取り消すことができません。
パフォーマンスのヒント:
イベントにサーバー処理が不要な場合は、イベントがサーバーに伝播されないよう、処理の最後にイベントを取り消すことを検討してください。「イベントがサーバーに伝播されないようにする方法」を参照してください。
ベスト・プラクティス:
キーボードおよびマウス・イベントは、元のDOMイベントへのアクセスを提供し、キー・コードやマウス座標などの取得用の便利な一連の関数も提供するAdfBaseEvent
クラスのAdfUIInputEvent
サブクラスを使用して、ネイティブDOMイベントをラップします。AdfBaseEvent
クラスは、これらのイベントの実装方法に関するブラウザの違いも考慮します。したがって、getNativeEvent()
メソッドを直接呼び出すことは避け、かわりにAdfUIInputEvent
APIを使用する必要があります。
clientListener
タグによって、クライアント側イベント・ハンドラ・スクリプトをコンポーネントに登録する宣言的方法が提供されます。サポートされているクライアント・イベント・タイプが発生すると、スクリプトが起動されます。次に、アクション・イベントに関連付けられているJavaScript関数の例を示します。
<af:button id="button0" text="Do something in response to an action"> <af:clientListener method="someJSMethod" type="action"/> </af:button>
ヒント
コンポーネントのJavaScriptプロパティのかわりにclientListener
タグを使用します。
すべてのADF Facesコンポーネントは、JSF 2.0クライアント動作APIをサポートします。ADF Facesコンポーネントのクライアント・イベントは、クライアント動作としても公開されます。クライアント動作タグ(f:ajax
など)では、クライアント動作に対応して実行されるJavaScriptをコンポーネントに宣言的に添付できます。たとえば、次のコードに、inputText
コンポーネントに添付されたf:ajax
タグを示します。このタグにより、change
クライアント・イベントがinputText
コンポーネントで発生したときにoutputText
コンポーネントがレンダリングされます。
af:inputText ...> <f:ajax name="change" render="ot1" execute="@this" /> </af:inputText> <af:outputText id="ot1" ... />
ADF Facesクライアント側イベント
表6-3に、ADF Facesクライアント・コンポーネントで生成されるイベント、イベントがサーバーに送信されるかどうか、イベントが取消し可能かどうか、およびイベントをトリガーするコンポーネントをリストします。
表6-3 ADF Facesクライアント・イベント
イベント・クラス | イベント・タイプ | サーバーへの伝播 | 取消し可能 | トリガー元コンポーネント |
---|---|---|---|---|
|
action |
はい |
はい |
すべてのコマンド・コンポーネント |
|
|
いいえ |
いいえ |
ページによってトリガーされます |
|
|
はい |
いいえ |
|
|
|
いいえ |
はい |
|
|
|
はい |
はい |
|
|
load |
はい |
はい |
PPRナビゲーションが使用されている場合でも、ドキュメントのコンテンツがクライアントに表示された後。onLoad DOMイベントに常に対応するとはかぎりません。 |
|
いいえ |
はい |
フォーカスを受け取ることのできる任意のコンポーネント |
|
|
|
いいえ |
はい |
|
|
event |
はい |
はい |
ユーザーがダイアログでOKボタンまたは取消しボタンを選択したとき |
|
event |
はい |
はい |
公開状態がユーザーによって切り替えられたとき |
|
inlineFrameLoad |
はい |
はい |
内部 |
|
|
はい |
いいえ |
ドラッグ・アンド・ドロップをサポートする任意のコンポーネント |
|
|
はい |
はい |
|
|
|
はい |
はい |
|
|
|
はい |
はい |
|
|
|
はい |
はい |
|
|
|
はい |
はい |
ポップアップが予期せず閉じられるか、cancelメソッドが呼び出された後 |
|
popupClosed |
いいえ |
いいえ |
ポップアップ・ウィンドウまたはダイアログが閉じた後 |
|
popupOpened |
いいえ |
いいえ |
ポップアップ・ウィンドウまたはダイアログが開いた後 |
|
popupOpening |
いいえ |
はい |
ポップアップ・ウィンドウまたはダイアログが開く前 |
|
propertyChange |
いいえ |
いいえ |
すべてのコンポーネント |
|
event |
はい |
はい |
問合せアクション時(ユーザーが検索アイコンまたは検索ボタンをクリックしたとき) |
|
event |
はい |
はい |
|
|
|
はい |
はい |
すべてのコマンド・コンポーネント |
|
|
はい |
はい |
|
|
|
はい |
はい |
|
|
rowDisclosure |
はい |
はい |
行の公開状態が切り替えられたとき |
|
|
表の表示イベントに対しては常に行われます。サーバー上の選択リスナーまたは公開リスナーの場合は◎です。 |
はい |
|
|
selection |
はい |
はい |
選択状態が変わったとき |
|
sort |
はい |
はい |
ユーザーが表のデータをソートしたとき |
|
valueChange |
はい |
はい |
すべての入力および選択コンポーネント( 入力または選択コンポーネントの値が変更されたとき |
表6-4に示すように、ADF Facesではクライアント・キーボードおよびマウス・イベントもサポートされます。
表6-4 サポートされるキーボードとマウスのイベント・タイプ
イベント・タイプ | イベントが発生するタイミング |
---|---|
|
ユーザーがコンポーネントをクリックしたとき |
|
ユーザーがコンポーネントをダブルクリックしたとき |
|
ユーザーがコンポーネント上でマウス・ボタンを押したとき |
|
ユーザーがコンポーネント上でマウス・ボタンを離したとき |
|
ユーザーがコンポーネント上でマウスを移動したとき |
|
コンポーネント内にマウスが移動したとき |
|
コンポーネントからマウスが移動したとき |
|
コンポーネントのフォーカス中にユーザーがキーを押したとき |
|
コンポーネントのフォーカス中にユーザーがキーを離したとき |
|
コンポーネントのフォーカス中にキーを押す動作が正常に完了したとき |
|
コンポーネントがキーボード・フォーカスを得たとき |
|
コンポーネントがキーボード・フォーカスを失ったとき |
クライアント側イベントの使用方法
クライアント側イベントを使用するには、まず、イベントを処理するJavaScriptを作成する必要があります。次に、clientListener
タグを使用します。
始める前に:
クライアント側イベントに関する知識が役立つ場合があります。「ADF Facesクライアント・イベントに対するJavaScriptの使用」を参照してください。
クライアント側イベントを使用する手順:
-
JavaScriptイベント・ハンドラ関数を作成します。JavaScriptの作成の詳細は、「JavaScriptのページへの追加」を参照してください。この機能内で次の点を追加できます。
-
ページでクライアント・コンポーネントを検索する
イベント・ハンドラを別のコンポーネントで動作させるには、ページでそのコンポーネントを検索する必要があります。たとえば、File Explorerアプリケーションで、ユーザーが「ヘルプ」メニューのフィードバックの送信メニュー項目を選択した場合、関連付けられたJavaScript関数はヘルプ・ポップアップ・ダイアログを開くためにそのダイアログを検索する必要があります。クライアント・コンポーネントの検索の詳細は、「ページでのクライアント・コンポーネントの検索」を参照してください。
-
イベントの元のソースを返す
ページに同じコンポーネントが複数ある場合、JavaScript関数はイベントを発行したコンポーネントを判断することが必要な場合があります。たとえば、複数のコンポーネントが同じポップアップ・ダイアログを開くことができ、そのダイアログをコール元コンポーネントに位置合せする必要があるとします。ポップアップ・ダイアログを位置合せする場所を決定するには、
AdfLaunchPopupEvent
のソースがわかっている必要があります。「イベントの発生元を返す方法」を参照してください。 -
クライアント属性の追加
クライアント・イベント・ハンドラは、コンポーネントの特定の属性を操作することが必要な場合があります。たとえば、File Explorerアプリケーションで、ユーザーが「ヘルプ」メニューで「バージョン情報」メニュー項目を選択した場合、ユーザーがフィードバックを提供できるダイアログが起動します。このダイアログを開いて表示するために使用される関数は、他のダイアログによっても使用され、異なる方法で表示されることが必要な場合があります。したがって、関数では、ダイアログの位置合せの方法に関する情報とともに、どのダイアログを表示するかを知っておく必要があります。この情報は、クライアント属性で搬送されます。クライアント属性は、クライアントへのカスタム・サーバー側属性のマーシャリングにも使用できます。「イベントのクライアント側属性の使用方法」を参照してください。
-
サーバーへの伝播を取り消す
一部のコンポーネントは、表6-3に示したようにサーバーにクライアント側イベントを伝播します。この追加処理が不要な場合は、その伝播を取り消すことができます。「イベントがサーバーに伝播されないようにする方法」を参照してください。
-
-
JavaScript関数の作成後、イベント・メソッドをコールするイベント・リスナーを追加する必要があります。
注意:
または、ADF Facesコンポーネントのすべてのクライアント・イベントはクライアント動作としても公開されるため、JSF 2.0クライアント動作タグ(
f:ajax
など)を使用してクライアント・イベントに応答できます。Java EE 6チュートリアル(http://download.oracle.com/javaee/index.html
)を参照してください-
JavaScriptを呼び出すコンポーネントを選択して、「プロパティ」ウィンドウでClientComponentをtrueに設定します。
-
「コンポーネント」ウィンドウの「操作」パネルで「リスナー」グループから「クライアント・リスナー」をドラッグし、選択したコンポーネントに子としてドロップします。
-
「クライアント・リスナーの挿入」ダイアログで、メソッドを入力し、JavaScript関数のタイプを選択します。
clientListener
タグのmethod
属性で、対応するイベントが発生したときにコールするJavaScript関数を指定します。JavaScript関数は1つのパラメータ(イベント・オブジェクト)をとる必要があります。clientListener
タグのtype
属性で、action
、valueChange
などのタグでリスニングするクライアント・イベント・タイプを指定します。表6-3に、ADF Facesクライアント・イベントをリストしています。clientListener
タグのtype
属性では、キーボードおよびマウスのイベントに関連するクライアント・イベント・タイプもサポートされます。表6-4に、キーボードとマウスのイベント・タイプを示しています。次の例に、
Explorer.js
JavaScriptファイルのshowHelpFileExplorerPopup
関数の起動に使用されるコードを示します。<af:commandMenuItem id="feedbackMenuItem" text="#{explorerBundle['menuitem.feedback']}" clientComponent="true"> <af:clientListener method="Explorer.showHelpFileExplorerPopup" type="action"/> </af:commandMenuItem>
-
「コンポーネント」ウィンドウで、関数によって必要とされる属性を追加するには、「操作」パネルから「クライアント属性」を、選択したコンポーネントへと子としてドラッグ・アンド・ドロップします。「プロパティ」ウィンドウに属性の値を入力します。次の例に、
showAboutFileExplorerPopup
関数の属性値の設定に使用されるコードを示します。<af:commandMenuItem id="aboutMenuItem" text="#{explorerBundle['menuitem.about']}" clientComponent="true"> <af:clientListener method="Explorer.showAboutFileExplorerPopup" type="action"/> <af:clientAttribute name="popupCompId" value=":fe:aboutPopup"/> <af:clientAttribute name="align" value="end_after"/> <af:clientAttribute name="alignId" value="aboutMenuItem"/> </af:commandMenuItem>
ベスト・プラクティス:
キーボードおよびマウス・イベントは、元のDOMイベントへのアクセスを提供し、キー・コードやマウス座標などの取得用の便利な一連の関数も提供する
AdfBaseEvent
クラスのAdfUIInputEvent
サブクラスを使用して、ネイティブDOMイベントをラップします。AdfBaseEvent
クラスは、これらのイベントの実装方法に関するブラウザの違いも考慮します。したがって、getNativeEvent()
メソッドを直接呼び出すことは避け、かわりにAdfUIInputEvent
APIを使用する必要があります。 -
イベントの発生元を返す方法
JavaScriptメソッドgetSource()
は、クライアント・イベントの元のソースを返します。たとえば、File Explorerアプリケーションには、次の例に示すshowAboutFileExplorerPopup
関数が含まれます。この関数は、値を渡すクライアント属性を使用して、特定のポップアップ・ダイアログまたはウィンドウに配置を設定するために複数のイベントによって使用できます。関数を使用する各イベントは属性に対して異なる値を持つため、関数は、対応する属性値にアクセスできるようにイベントを起動したソースについて知っておく必要があります(クライアント属性の使用の詳細は、「イベントのクライアント側属性の使用方法」を参照してください)。
Explorer.showAboutFileExplorerPopup = function(event)
{
var source = event.getSource();
var alignType = source.getProperty("align");
var alignCompId = source.getProperty("alignId");
var popupCompId = source.getProperty("popupCompId");
source.show({align:alignType, alignId:alignCompId});
event.cancel();
}
getSource()
メソッドがコールされ、現在のフォーカス・イベントを発生したクライアント・コンポーネント(このケースではポップアップ・コンポーネント)が決まります。
イベントのクライアント側属性の使用方法
スクリプト・ロジックによってコンポーネントになんらかの変更を加えることが必要になる場合があります。これを行うには、イベントによって渡された属性値が必要な場合があります。たとえば、File Explorerアプリケーションには、次の例に示すshowAboutFileExplorerPopup
関数が含まれます。この関数は、値を渡すクライアント属性を使用して、特定のポップアップ・コンポーネントに配置を設定するために使用できます。属性値は、ソース・コンポーネントでgetProperty
メソッドを呼び出すことでアクセスされます。
Explorer.showAboutFileExplorerPopup = function(event) { var source = event.getSource(); var alignType = source.getProperty("align"); var alignCompId = source.getProperty("alignId"); var popupCompId = source.getProperty("popupCompId"); var aboutPopup = event.getSource().findComponent(popupCompId); aboutPopup.show({align:alignType, alignId:alignCompId}); event.cancel(); }
次の例に示すように、値はソース・コンポーネントで設定されます。
<af:commandMenuItem id="aboutMenuItem" text="#{explorerBundle['menuitem.about']}" clientComponent="true"> <af:clientListener method="Explorer.showAboutFileExplorerPopup" type="action"/> <af:clientAttribute name="popupCompId" value=":aboutPopup"/> <af:clientAttribute name="align" value="end_after"/> <af:clientAttribute name="alignId" value="aboutMenuItem"/> </af:commandMenuItem>
このように属性を使用すると、同じイベントをトリガーする異なるコンポーネントでスクリプトを再利用できます。
イベント実行時のUI入力のブロック方法
実行時間が長いイベントの処理中に、ユーザーがUIを操作できないようにする場合があります。たとえば、アプリケーションがボタンを使用して命令を送信し、処理の一部にユーザーのアカウントに対する請求を作成する処理が含まれているとします。ユーザーが不注意でボタンを2回押した場合、そのアカウントは2回請求されることになります。サーバーの処理が完了するまでユーザーの操作をブロックすることで、誤ったクライアント・アクティビティが発生しないようにできます。
ADF Faces JavaScript APIには、AdfBaseEvent.preventUserInput
関数が含まれます。イベントの処理中にすべてのユーザー入力を阻止するためにpreventUserInput
関数をコールすると、ブラウザ・ウィンドウ全体にグラス・ペインが表示され、イベントがサーバーとのラウンドトリップを完了するまでそれ以上入力できなくなります。
preventUserInput
関数は、カスタム・イベント、カスタム・クライアント・スクリプトで発生したイベント、またはカスタム・クライアント・コンポーネントのピアで発生したイベントでのみ使用できます。また、イベントをサーバーに伝播する必要があります。次の例に、JavaScriptでpreventUserInput
を使用する方法を示します。
function queueEvent(event) { event.cancel(); // cancel action event var source = event.getSource(); var params = {}; var type = "customListener"; var immediate = true; var isPartial = true; var customEvent = new AdfCustomEvent(source, type, params, immediate); customEvent.preventUserInput(); customEvent.queue(isPartial); }
イベントがサーバーに伝播されないようにする方法
一部のクライアント・イベントは、クライアントでの処理が完了すると、デフォルトでサーバーに伝播されます。この伝播が行われないようにすることが必要な状況もあります。たとえば、ボタンがクリックされるとJavaScriptコードを実行するbutton
コンポーネントを使用している場合、サーバーにactionListener
イベント・リスナーがなければ、イベントを伝播してもリソースの無駄使いになります。サーバーへ伝播されないようにするには、リスナーでイベントのcancel()
関数をコールします。cancel()
関数がコールされると、isCanceled()
関数でtrue
が返されます。
次の例に、伝播を取り消すshowAboutFileExplorerPopup
関数を示します。
Explorer.showAboutFileExplorerPopup = function(event)
{
var source = event.getSource();
var alignType = source.getProperty("align");
var alignCompId = source.getProperty("alignId");
var popupCompId = source.getProperty("popupCompId");
var aboutPopup = event.getSource().findComponent(popupCompId);
aboutPopup.show({align:alignType, alignId:alignCompId});
event.cancel();
}
イベントを取り消すことで、行われないデフォルト処理もあります。たとえば、ポップアップ・メニューのAdfUIInputEvent
イベントを取り消すと、このイベントを受けて表示されるポップアップ・メニューがブラウザで表示されません。
cancel()
関数コールは、イベントを取り消せない場合に無視されます。イベントは、isCancelable()
関数からfalse
を返すことでこれを示します(取消しできないイベントは、表6-3の「取消し可能」列に「×」が表示されています)。これは一般に、イベントが、結果がすでに完了し、ブロックできないという通知であることを意味します。また、取り消された後でイベントの取消しを元に戻す方法はありません。
レスポンスが必要でないことを示す方法
フレームワークにイベントのレスポンスの処理を期待しない場合があります。たとえば、表のコンテンツをスプレッドシートにエクスポートする場合、コールから戻るのを待つ必要はありません。フレームワークにレスポンスが不要であることを通知するには、AdfBaseEvent.noResponseExpected()
メソッドを使用します。
実行時の処理: クライアント側イベントの機能の仕方
一般に、イベント処理はブラウザのネイティブ・イベント・ループから取得されます。ページは、ドキュメントをバブル・アップするすべてのDOMイベントを受け取り、DOMのその部分に関連付けられているピアに渡します。ピアは、DOMイベントをラップするJavaScriptイベント・オブジェクトの作成を担当し、イベントをキューに入れるページに返します(ピアおよびADF Facesアーキテクチャの詳細は、「ADF Facesクライアント側アーキテクチャの使用方法」を参照してください)。
各DOMイベントのページでの処理(この結果、通常コンポーネント・イベントがキューイングされる)後、ページのイベント・キューは、通常ブラウザのイベント・ループの最後で空になります。ただし、タイマー起動時にポーリング・イベントを発生するポーリング・コンポーネントなど、ユーザー入力とは無関係にイベントがキューイングされることがあるため、イベントをキューイングすると、ユーザー入力がなくても、イベント・キューを空にするタイマーも起動されます。
イベント・キューは先入れ先出しキューです。イベント・キューを空にするには、ページで各イベント・オブジェクトを捕捉し、イベント・ソースのbroadcast()
関数に配信します。このループは、キューが空になるまで続きます。イベントのブロードキャストによって、導出された新規イベントのキューイングが間接的に引き起こされることは非常に理にかなっています(一般的です)。導出されたイベントは、同じループでブロードキャストされます。
イベントがコンポーネントにブロードキャストされると、コンポーネントで次の処理が行われます。
-
イベントをピアの
DispatchComponentEvent
メソッドに配信します。 -
そのイベント・タイプ用に登録されているリスナーにイベントを配信します。
-
イベントをバブルする必要があるかどうかを確認し、必要な場合はバブルを開始します。ほとんどのイベントがバブルされます。例外には、プロパティ変更イベント(キューイングされず、このプロセスにまったく関与しない)やマウスの移動イベント(効率を高めるため)があります。
イベントがバブルされるとき、イベントは
AdfUIComponent
のHandleBubbledEvent
関数に配信され、ここからピアのDispatchComponentEvent
関数に渡されます。クライアント・イベント・リスナーではなく、ピアがイベントを受け取ることに注意してください。イベントのバブルは、イベントの
stopBubbling()
関数をコールすることでブロックされます。その後で、isBubblingStopped()
関数はtrue
を返し、バブルは続行されません。取消しと同様に、このコールは元に戻せません。注意:
イベントを取り消してもバブルは止まりません。イベントの取消しとバブルの停止の両方を行う場合は、両方の関数をコールする必要があります。
-
前述の処理でイベントが取り消されない場合は、
AdfUIComponent.HandleEvent
メソッドをコールします。このメソッドでは、イベントでのリクエストに応じてイベントがサーバー・イベント・キューに追加されます。
ネーミング・コンテナの使用に関する必知事項
ADF Facesのいくつかのコンポーネントは、pageTemplate
、subform
、table
およびtree
などのNamingContainer
コンポーネントです。NamingContainer
コンポーネントを含むページでクライアント側APIとイベントを使用する場合、ソース・コンポーネントでfindComponent()
メソッドを使用する必要があります。
たとえば、次の例に示すように、File Explorerアプリケーション内のいずれかのページのすべてのコンポーネントは最終的にpageTemplate
コンポーネント内に存在するため、JavaScript関数はgetSource()
およびfindComponent()
メソッドを使用する必要があります。getSource()
メソッドは、コンポーネントの検索に使用できるAdfUIComponent
クラスにアクセスします。
function showPopup(event) { event.cancel(); var source = event.getSource(); var popup = source.findComponent("popup"); popup.show({align:"after_end", alignId:"button"}); }
findComponent()
メソッドを使用すると、メソッドを起動したコンポーネントでローカルに検索が開始します。ネーミング・コンテナの使用の詳細は、「ページでのクライアント・コンポーネントの検索」を参照してください。
クライアントからサーバーへのカスタム・イベントの送信
ADF Facesでは、カスタム・イベントを使用して任意のカスタム・データをクライアントからサーバーに返送できます。クライアントからサーバーへカスタム・イベントを送信するには、カスタム・イベント・タイプを使用してクライアント・イベントを起動し、バッキングBeanにサーバー・リスナー・メソッドを記述して、このメソッドでカスタム・イベントを処理したうえで、サーバー・リスナーをコンポーネントに登録します。
clientAttribute
タグでは、サーバーからクライアントへのボーナス属性の送信はサポートされますが、これらの属性のサーバーへの同期化は行われません。カスタム・データをサーバーに戻すには、AdfCustomEvent
クラスとserverListener
タグを使用して送信されるカスタム・イベントを使用します。
AdfCustomEvent.queue()
JavaScriptメソッドによって、clientComponent
属性がtrue
に設定されているコンポーネントからカスタム・イベントを起動できます。カスタム・イベント・オブジェクトには、クライアント・イベント・ソースと、イベントに含まれるパラメータのマップに関する情報が含まれます。カスタム・イベントは即時配信(リクエスト値の適用フェーズ中)にも非即時配信(アプリケーションの起動フェーズ中)にも設定できます。
たとえば、File Explorerアプリケーションでは、ユーザーは左側の検索フィールドにファイル名を入力した後、[Enter]キーを押して検索を起動します。次の例に示すように、これは、inputText
フィールドに、[Enter]キーが押されると、JavaScript関数を起動するclientListener
が含まれているためです。
//Code on the JSF page... <af:inputText id="searchCriteriaName" value="#{explorer.navigatorManager.searchNavigator. searchCriteriaName}" shortDesc="#{explorerBundle['navigator.filenamesearch']}"> <af:serverListener type="enterPressedOnSearch" method="#{explorer.navigatorManager. searchNavigator.searchOnEnter}"/> <af:clientListener type="keyPress" method="Explorer.searchNameHandleKeyPress"/> </af:inputText> //Code in JavaScript file... Explorer.searchNameHandleKeyPress = function (event) { if (event.getKeyCode()==AdfKeyStroke.ENTER_KEY) { var source = event.getSource(); AdfCustomEvent.queue(source, "enterPressedOnSearch", {}, false); } }
JavaScriptには、イベント・ソース、カスタム・イベント・タイプとして文字列enterPressedOnSearch
、nullパラメータ・マップ、即時パラメータにFalse
をとるAdfCustomEvent.queue
メソッドが含まれています。
ページのinputText
にも、次のserverListener
タグが含まれています。
<af:serverListener type="enterPressedOnSearch"
method="#{explorer.navigatorManager.
searchNavigator.searchOnEnter}"/>
タイプ値enterPressedOnSearch
がJavaScriptのAdfCustomEvent.queue
メソッドのパラメータの値と同じであるため、メソッド式#{explorer.navigatorManager.searchNavigator.searchOnEnter}
に解決されるメソッドが起動されます。
クライアントからサーバーへのカスタム・イベントの送信方法
クライアントからサーバーへカスタム・イベントを送信するには、カスタム・イベント・タイプを使用してクライアント・イベントを起動し、バッキングBeanにサーバー・リスナー・メソッドを記述し、このメソッドでカスタム・イベントを処理する必要があります。次に、サーバー・リスナーをコンポーネントに登録します。
始める前に:
サーバーへのカスタム・イベントの送信に関する知識が役立つ場合があります。「クライアントからサーバーへのカスタム・イベントの送信」を参照してください。
カスタム・イベントを送信する手順:
実行時の処理: クライアント・リスナーとサーバー・リスナーの協働の仕方
実行時、[Enter]キーを押すなど、ユーザーによってイベントが発生すると、クライアント・リスナー・スクリプトが実行されます。このスクリプトでAdfCustomEvent.queue()
メソッドをコールし、指定したイベント・タイプのカスタム・イベントが入力コンポーネントのキューに置かれます。入力コンポーネントに登録されているサーバー・リスナーがカスタム・イベントを受け取り、関連付けられているBeanメソッドが実行されます。
データのマーシャリングとアンマーシャリングに関する必知事項
マーシャリングとアンマーシャリングは、プログラミング言語のデータ・オブジェクトをバイト・ストリームに変換し、同じまたは別のプログラミング言語のネイティブ・データ・オブジェクトに戻すプロセスです。ADF Facesでは、マーシャリングとアンマーシャリングは、データを適切な形式に変換して、クライアント上のJavaScriptとサーバー側のJava間で最適に交換できるようにすることを意味します。
変換処理中に情報が失われる可能性あることに注意してください。たとえば、次の例に示すように、カスタム・イベントを使用して数値1
と文字列test
を送信するとします。
AdfCustomEvent.queue(event.getSource(), "something", {first:1, second:"test"});
JavaScriptからJavaへの変換では数値はDoubles
に変換されるため、サーバー側リスナーでfirst
パラメータの型がjava.lang.Double
になります。ただし、初めはサーバー側でint
だったパラメータが、JavaからJavaScriptへの変換で数値になった可能性もあります。サーバーへ戻る際にDouble
に変換されます。
JavaとJavaScriptのマッピングにより、Java型とJavaScript型間のマッピングが提供されます。
JavaとJavaScriptのマッピング
表6-5に、JavaScript型とADF Facesの対応するJava型とのマッピングを示します。
表6-5 JavaScriptとJavaの型マップ
JavaScript型 | Java型 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
表6-6に、Java型とJavaScript型のマッピングを示します。
表6-6 JavaとJavaScriptの型マップ
Java型 | JavaScript型 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
イベント・レスポンス内でのスクリプトの実行
クライアント側に特定の操作を実行するJavaScriptライブラリがあり、サーバー側であるアクションの実行後にそのライブラリの関数をコールしたいときには、イベント・レスポンス内でJavaScriptを実行すると便利です。
ExtendedRenderKitService
クラスを使用すると、アクション・メソッド・バインディングの起動後などのイベント・レスポンスにJavaScriptを追加できます。これは、ユーザーにデータベース接続が確立できないことを通知するアラートの送信などの簡単なメッセージの場合もあれば、プログラムからポップアップ・ダイアログを終了させるためのポップアップ・ウィンドウでのhide()
などの関数のコールの場合もあります。
たとえば、File ExplorerアプリケーションでユーザーがUpOneFolder
ナビゲーション・ボタンをクリックしてフォルダ構造を上に移動すると、フォルダ・ペインが再描画されて、選択した親フォルダが表示されます。UpOneFolder
ボタン・イベントのクリックを受けてHandleUpOneFolder()
メソッドがコールされます。ExtendedRenderKitService
クラスを使用してJavaScriptがレスポンスに追加されます。
次の例に、actionListener
属性が、ボタンがクリックされたときにアクション・イベントを処理するHandleUpOneFolder()
ハンドラ・メソッドにバインドされているページのUpOneFolder
コードを示します。
<af:btton id="upOneFolder"
. . .
actionListener="#{explorer.headerManager.handleUpOneFolder}"/>
次の例に、ExtendedRenderKitService
クラスを使用するhandleUpOneFolder
メソッドを示します。
public void handleUpOneFolder(ActionEvent actionEvent) { UIXTree folderTree = feBean.getNavigatorManager().getFoldersNavigator().getFoldersTreeComponent(); Object selectedPath = feBean.getNavigatorManager().getFoldersNavigator().getFirstSelectedTreePath(); if (selectedPath != null) { TreeModel model = _feBean.getNavigatorManager().getFoldersNavigator().getFoldersTreeModel(); Object oldRowKey = model.getRowKey(); try { model.setRowKey(selectedPath); Object parentRowKey = model.getContainerRowKey(); if (parentRowKey != null) { folderTree.getSelectedRowKeys().clear(); folderTree.getSelectedRowKeys().add(parentRowKey); // This is an example of how to force a single attribute // to rerender. The method assumes that the client has an optimized // setter for "selectedRowKeys" of tree. FacesContext context = FacesContext.getCurrentInstance(); ExtendedRenderKitService erks = Service.getRenderKitService(context, ExtendedRenderKitService.class); String clientRowKey = folderTree.getClientRowKeyManager(). getClientRowKey(context, folderTree, parentRowKey); String clientId = folderTree.getClientId(context); StringBuilder builder = new StringBuilder(); builder.append("AdfPage.PAGE.findComponent('"); builder.append(clientId); builder.append("').setSelectedRowKeys({'"); builder.append(clientRowKey); builder.append("':true});"); erks.addScript(context, builder.toString()); } } finally { model.setRowKey(oldRowKey); } // Only really needed if using server-side rerendering // of the tree selection, but performing it here saves // a roundtrip (just one, to fetch the table data, instead // of one to process the selection event only after which // the table data gets fetched!) _feBean.getNavigatorManager().getFoldersNavigator().openSelectedFolder(); } }
ADF Facesのクライアント動作タグの使用
ADF Facesのクライアント動作タグは、クライアント側で実行されます。ADF Facesは、クライアント・リスナーのかわりに使用できる次のクライアント動作タグのリストを提供します。
クライアント側での動作を実装する場合、通常はJavaScriptを記述し、それをクライアント・リスナーとしてコンポーネントに登録する必要がありますが、ADF Facesのクライアント動作タグを使用すると、一般的なクライアント操作を宣言的に実行できます。JavaScriptコードを記述するかわりにこれらのタグを使用して同じ処理を実装すると、ブラウザにダウンロードする必要のあるJavaScriptコードの量が少なくなります。
ADF Facesは、クライアント・リスナーのかわりに使用できる次のクライアント動作タグを提供します。
-
panelDashboardBehavior
: 応答性を向上させるために、実行時にpanelDasboard
コンポーネントに子コンポーネントを挿入できます。「panelDashboardコンポーネントの使用方法」を参照してください。 -
insertTextBehavior
: コマンド・コンポーネントで、inputText
コンポーネントのカーソル位置にテキストを挿入できます。「inputTextコンポーネントへのテキストの挿入機能の追加方法」を参照してください。 -
richTextEditorInsertBehavior
: コマンド・コンポーネントで、richTextEditor
コンポーネントのカーソル位置にテキスト(事前フォーマット済テキストを含む)を挿入できます。「richTextEditorコンポーネントへのテキストの挿入機能を追加する方法」を参照してください。 -
autoSuggestBehavior
: ユーザーが入力する内容に一致するドロップダウン・リストの項目を値リスト・コンポーネントに表示できるようにします。「値リスト・コンポーネントについて」を参照してください。 -
showPopupBehavior
: コマンド・コンポーネントでポップアップ・コンポーネントを起動できます。「ポップアップの宣言的な呼出し」を参照してください。 -
showPrintablePageBehavior
: コマンド・コンポーネントで、ページの印刷可能版を生成して表示できます。「印刷用のページの表示」を参照してください。 -
checkUncommittedDataBehavior
: immediate属性がtrueに設定されている場合にユーザーがページ外へのナビゲートを試行したときに、コマンド・コンポーネントが警告を表示できるようにします。詳細は、「ナビゲーション・コンポーネントの使用」を参照してください。 -
scrollComponentIntoViewBehavior
: クリックして、コマンド・コンポーネントから名前付きのコンポーネントに移動できます。「scrollComponentIntoViewBehaviorタグの使用方法」を参照してください。ヒント
ADF Facesは、スクロールされるコンポーネントがページにまだレンダリングされていない場合に使用できるサーバー側
scrollComponentIntoView
APIも提供します。たとえば、表を特定の行にスクロールできるようにする場合に、表が最初にレンダリングされるときに行がビューの範囲外になることがあります。
scrollComponentIntoView
APIをデータ・フェッチ・イベントの一部として使用できます。Java APIリファレンスfor Oracle ADF Facesを参照してください。 -
target
: 指定されたイベントが発生したときに、コンポーネントを宣言的に実行するか、コンポーネントのリストを表示します。「targetタグを使用したPPRの実行」を参照してください。
クライアント動作タグで、サーバー側イベント配信が自動的に取り消されます。したがって、親コンポーネントのactionListener
またはaction
属性が無視されます。これは無効にすることができません。サーバー側の機能もトリガーする場合は、クライアント側イベントを使用する(「ADF Facesクライアント・イベントに対するJavaScriptの使用」を参照)か、AdfCustomEvent
およびaf:serverListener
を使用してサーバー側イベントを配信するクライアント・リスナーを追加します(「クライアントからサーバーへのカスタム・イベントの送信」を参照)。
scrollComponentIntoViewBehaviorタグの使用方法
ユーザーがページの特定のコンポーネントに移動できるようにする場合は、scrollComponentIntoViewBehavior
タグを使用します。このアクションは、HTMLのアンカーと似ています。たとえば、commandLink
コンポーネントを使用して、ユーザーがページの特定の部分に移動できるようにできます。richTextEditor
およびinlineFrame
コンポーネントの場合は、サブコンポーネントに移動できます。たとえば、図6-1は、そのテキストに多数のセクションがあるrichTextEditor
コンポーネントを示しています。エディタの下にあるコマンド・リンクを使用すると、テキストの特定部分に移動できます。
図6-1 エディタのscrollComponentIntoViewBehaviorタグ
ユーザーがスクロールしたコンポーネントにフォーカスを切り替えるためのタグを構成することもできます。
始める前に:
動作タグに関する知識が役立つ場合があります。「ADF Facesのクライアント動作タグの使用」を参照してください。
scrollComponentIntoViewBehaviorタグを使用する手順:
ポーリング・イベントを使用したページの更新
ADF Faces pollコンポーネントを使用すると、ページ・コンポーネントを定期的に更新する手段として、サーバーにポーリング・イベントを送信することができます。ポーリング・コンポーネントを使用するには、ポーリング・イベントの機能を処理するハンドラ・メソッドを作成する必要があります。
ADF Facesは、pollEvent
を使用して指定された間隔でサーバーと通信できるpollコンポーネントを提供します。たとえば、ポーリング・コンポーネントを使用して、outputText
コンポーネントを更新したり、サーバーにハートビートを配信して、それらのセッションがタイムアウトするのを防ぐことができます。
ポーリング時刻に必要な処理を行うために使用されるpollEvent
のリスナーを作成する必要があります。たとえば、pollコンポーネントを使用してoutputText
コンポーネントの値を更新する場合は、データ・ソース内の値をチェックしてからコンポーネントを更新するpollEventListener
メソッドを実装します。
pollコンポーネントがそのポーリング・イベントを配信する頻度を決定する時間間隔を構成できます。経過後にページがタイムアウトになることを許可される時間も構成します。ページのポーリングはセッションがタイムアウトにならない原因となるため、これが役立つ場合があります。サーバーにリクエストが送信されるたびに、セッション・タイムアウト値がページに書き込まれ、セッションをいつタイムアウトにするかを決定します。pollコンポーネントは(時間間隔に基づいて)サーバーにリクエストを継続的に送信するため、セッションは決してタイムアウトになりません。これは、ネットワーク使用量とメモリーの両方でコストが高くなります。
この問題を回避するために、web.xml
構成ファイルには、タイムアウトにする前にページを実行する必要のある時間の長さを指定するoracle.adf.view.rich.poll.TIMEOUT
コンテキスト・パラメータが含まれます。キーボードやマウスのアクティビティがない場合、ページはタイムアウトに対して適格とみなされます。デフォルトのタイムアウト時間は10分です。このため、ユーザーが10分間非アクティブの(つまり、キーボードやマウスを使用していない)場合、フレームワークはポーリングを停止し、その時点から、ページは標準サーバー側セッション・タイムアウトに参加します(「セッション・タイムアウトの警告」を参照してください)。
アプリケーションがタイムアウトになる場合、ユーザーがマウスを移動するかキーボードを再び使用すると、新しいセッション・タイムアウト値がページに書き込まれ、ポーリングが再び開始します。
pollコンポーネントのtimeout
属性を使用して、特定のページについてこの時間をオーバーライドできます。
pollコンポーネントの使用方法
pollコンポーネントを使用する場合、通常はポーリング・イベントの機能を処理するハンドラ・メソッドも作成します。
始める前に:
属性が機能に与える影響に関する知識が役立つ場合があります。「ポーリング・イベントを使用したページの更新」を参照してください。
pollコンポーネントを使用する手順: