ヘッダーをスキップ
Oracle Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド
11gリリース1(11.1.1)
B52029-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

3 ADF Facesアーキテクチャの使用

この章では、ADF Facesアーキテクチャの主な機能を概説します。また、クライアント側アーキテクチャの異なる機能の使用に関する情報も提供します。

この章に含まれる項は次のとおりです。

3.1 ADF Facesアーキテクチャの使用の概要

ADF Facesリッチ・クライアント・フレームワーク(RCF)には、AJAXタイプの機能をWebアプリケーションに作成するために必要な機能が多く用意されており、すべてフレームワークに組み込まれています。これらの機能の多くは、アーキテクチャのクライアント側にあります。RCFの基本は、クライアント側コンポーネント・モデルにあまり移入されないことです。クライアント・コンポーネントは、必要な場合にのみ存在します。これは、clientListenerハンドラが登録されている場合、あるいはページ開発者がクライアント側のコンポーネントと対話する必要があり、クライアント・コンポーネントが使用できるよう構成してある場合のいずれかです。

クライアント・コンポーネントが存在する主な理由は、フレームワークおよび開発者に対するAPI規定を提供することです。クライアント側コンポーネントは、イベント処理がサポートされる簡単なプロパティ・コンテナとみなすことができます。クライアント・コンポーネントは、状態を格納し、APIを提供するためにのみ存在するため、Document Object Model(DOM)と直接対話しません。DOMとのすべての対話は、ピアと呼ばれる媒介を使用して行われます。フレームワークの内部動作の大部分は、意識する必要がありません。JDeveloperとADF Facesを組み合せて使用すると、アーキテクチャ上の機能の多くを宣言して使用でき、コードを作成する必要がありません。

たとえば、RCFでは、各サーバー側コンポーネントに対応するクライアント・コンポーネントをすべて作成するわけではないため、クライアント版のコンポーネント・インスタンスが必要な場合もあります。3.4項「クライアント側コンポーネントのインスタンス化」に、これを宣言的に行う方法が説明されています。JDeveloperのプロパティ・インスペクタを使用して、3.8項「レンダリングおよび可視性の理解」で説明されている、コンポーネントをレンダリングするかどうか、あるいは非表示にするかどうかを決めるプロパティを設定します。

他の機能には、ADF Faces JavaScript APIを使用する必要があるものもあります。たとえば、3.5項「ページでのクライアント・コンポーネントの検索」に、APIを使用して特定のクライアント側コンポーネントを検索する方法が説明されています。また、3.6項「クライアントでのコンポーネント・プロパティへのアクセス」に、特定のプロパティへのアクセス方法が記載されています。

次のRCF機能はより複雑です。このため、個別の章が使用されています。

この章の以降の項では、クライアント側フレームワークの使用に焦点を当てます。

3.2 クライアント・イベントのリスニング

従来の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関数に作成します。

例3-2 JavaScriptイベント・ハンドラ

function sayHello()
  {
    alert("Hello, world!")
  }

クライアント版のコンポーネントがあるため、ボタンがクリックされると、AdfActionクライアント・イベントが起動されます。AdfActionイベントをリスニングするようclientListenerタグが構成されているため、sayHello関数が実行されます。クライアント側イベントの詳細は、5.3項「ADF Facesクライアント・イベントに対するJavaScriptの使用」を参照してください。

3.3 JavaScriptのページへの追加

JavaScriptをページにインラインで直接追加することも、JavaScriptライブラリをページにインポートすることもできます。ライブラリをインポートすると、ページのコンテンツ・サイズが小さくなります。ライブラリはページ間で共有でき、ブラウザでキャッシュできます。可能な場合はJavaScriptライブラリをインポートします。インラインのJavaScriptは、小規模でページ固有のスクリプトが必要な場合にのみ使用します。


パフォーマンスのヒント:

必要なページにのみJavaScriptを含めることで、パフォーマンスが向上します。これは、テンプレートにJavaScriptが含まれている場合のように、JavaScriptの不要なページでJavaScriptをロードする必要がないためです。ただし、ほとんどのページで同じJavaScriptコードが使用されている場合、テンプレートにライブラリをインポートするスクリプトまたはタグを含めることを検討します。

ただし、JavaScriptコード・ライブラリが非常に大きくなった場合、ライブラリを内容に応じて分割し、(テンプレートではなく)ページで必要な部分のみを含めることに注意してください。この方法で、ブラウザ・キャッシュが使用され、ページのHTMLコンテンツが小さくなるため、パフォーマンスが向上します。


3.3.1 インラインのJavaScriptの使用方法

インラインのJavaScriptは、JSFアプリケーションと同様に作成および使用します。JavaScriptがページに含まれる場合、clientListenerタグを使用して起動します。

インラインのJavaScriptを使用する手順:

  1. 例3-5に太字で示すコードを追加して、MyFaces Trinidadタグ・ライブラリをページのルート要素に追加します。

    例3-3 ページでのMyFaces Trinidadタグ・ライブラリ

    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
              xmlns:f="http://java.sun.com/jsf/core"
              xmlns:h="http://java.sun.com/jsf/html"
              xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
              xmlns:trh="http://myfaces.apache.org/trinidad/html"
    
  2. ページにJavaScriptを作成します。

    たとえば、例3-2に示すsayHello関数は、例3-4のようにJSFページに含めることができます。

    例3-4 インラインのJavaScript

    <trh:script>
      function sayHello()
      {
        alert("Hello, world!")
      }
    </trh:script>
    

    注意:

    ページまたはテンプレートにf:verbatimタグを使用してJavaScriptを指定しないでください。

    RCFでは、PPRレスポンス・ペイロードの特別なセクションにスクリプトが配置されます。これにより、異なるブラウザ間で一貫して動作するAPIを使用して、クライアントでスクリプトを実行できます。RCFは、<trh:script>タグを使用するスクリプトを検出および移動のみできます。


  3. 構造ウィンドウで、JavaScriptを起動するコンポーネントを右クリックし、「<コンポーネント>の中に挿入」「ADF Faces」「クライアント・リスナー」と選択します。

  4. 「クライアント・リスナーの挿入」ダイアログで「メソッド」フィールドにJavaScript関数の名前を入力します。タイプ・フィールドで、関数を起動するイベント・タイプを選択します。

3.3.2 JavaScriptライブラリのインポート方法

MyFaces Trinidadのtrh:scriptタグを使用して、ページからJavaScriptライブラリにアクセスします。このタグは、documentタグのmetaContainerファセットの内部に含める必要があります。

ページからJavaScriptライブラリにアクセスする手順:

  1. 例3-5に太字で示すコードを追加して、MyFaces Trinidadタグ・ライブラリをページのルート要素に追加します。

    例3-5 ページでのMyFaces Trinidadタグ・ライブラリ

    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
              xmlns:f="http://java.sun.com/jsf/core"
              xmlns:h="http://java.sun.com/jsf/html"
              xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
              xmlns:trh="http://myfaces.apache.org/trinidad/html"
    
  2. documentタグの下に、例3-6に太字で示すコードを追加し、JavaScriptライブラリが含まれるディレクトリへの相対パスに/mySourceDirectoryを置き換えます。

    例3-6 JavaScriptライブラリへのアクセス

    <af:document>
      <f:facet name="metaContainer">
        <trh:script source="/mySourceDirectory"/>
      </facet>
      <af:form></af:form>
    </af:document>
    
  3. 構造ウィンドウで、JavaScriptを起動するコンポーネントを右クリックし、「<コンポーネント>の中に挿入」「ADF Faces」「クライアント・リスナー」と選択します。

  4. 「クライアント・リスナーの挿入」ダイアログで「メソッド」フィールドに関数の完全修飾名を入力します。たとえば、sayHello関数がMyScriptsライブラリにある場合、MyScripts.sayHelloと入力します。タイプ・フィールドで、関数を起動するイベント・タイプを選択します。

3.3.3 クライアント・イベント・ソースへのアクセスについて

JavaScriptでクライアントにアクセスする必要がある場合、リスナーのコンテキストで行われ、イベントのソース・コンポーネントにアクセスする必要がある場合がしばしばあります。getSource()メソッドを使用してクライアント・コンポーネントを取得します。例3-7に、名前を表示するためにソース・クライアント・コンポーネントにアクセスするsayHello関数を示します。

例3-7 クライアント・イベント・ソースへのアクセス

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.6項「クライアントでのコンポーネント・プロパティへのアクセス」を参照してください。実行時のクライアント・イベントの処理の詳細は、5.3.6項「実行時の処理: クライアント側イベントの機能の仕方」を参照してください。

3.4 クライアント側コンポーネントのインスタンス化

RCFでは、どのコンポーネントが、対応するクライアント側コンポーネント・インスタンスをデフォルトで持つかについて保証されません。通常、clientListenerハンドラを登録して、クライアント側コンポーネントと対話します。登録されているclientListenerハンドラがコンポーネントにある場合、コンポーネントはクライアント側表現を自動的に持ちます。クライアントの別のコンポーネントにアクセスする必要がある場合、clientComponent属性をtrueに設定して、そのコンポーネントがクライアントで使用できるよう明示的に構成します。


パフォーマンスのヒント:

クライアントのコンポーネントとプログラムで対話する場合にのみclientComponenttrueに設定します。

clientComponent属性をtrueに設定すると、コンポーネントのAdfUIComponentクラスのインスタンスがフレームワークで作成されます。これによって、クライアント側で使用できるAPIが提供されます。クラスでは、基本的なプロパティ・アクセッサ・メソッド(getProperty()setProperty()など)、イベント・リスナーの登録およびイベント配信関連のAPIが提供されます。フレームワークには、プロパティ固有のアクセッサ・メソッド(getText()setText()など)を公開するレンダラ固有のサブクラス(AdfRichOutputTextなど)も用意されています。これらのアクセッサ・メソッドは、AdfUIComponentクラスのgetおよびsetProperty()メソッドをラップするのみのラッパーで、コーディングが簡便になるよう用意されています。

たとえば、sayHello関数から値(表示するテキスト)を取得するoutputTextコンポーネントがページにあるとします。この関数は、値を設定するためにoutputTextコンポーネントにアクセスできる必要があります。これが機能するには、クライアント側バージョンのoutputTextコンポーネントがある必要があります。例3-8に、JSFページ・コードを示します。outputTextコンポーネントにID値があり、clientComponent属性がtrueに設定されていることに注意してください。また、値はJavaScriptで設定されるため、例には値がないことにも注意してください。

例3-8 コンポーネントの追加

<af:commandButton text="Say Hello">
  <af:clientListener method="sayHello" type="action"/>
</af:commandButton>

<af:outputText id="greeting" value="" clientComponent="true">

outputTextにクライアント側表現があるため、JavaScriptでこれを見つけて使用できます。

3.5 ページでのクライアント・コンポーネントの検索

イベントのソースではないクライアント・コンポーネントを検索する必要がある場合、AdfUIComponent.findComponent(expr)メソッドを使用できます。これはJSFのUIComponent.findComponent()メソッドと似ており、指定した検索式に合致するIDを使用してUIComponentオブジェクトを検索して返します。AdfUIComponent.findComponent(expr)メソッドは、サーバーではなくクライアントでのみ機能します。

例3-9に、コンポーネントのIDを使用してoutputTextコンポーネントを検索するsayHello関数を示します。

例3-9 findComponent()を使用したクライアント・コンポーネントの検索

function sayHello(actionEvent)
{
  var component=actionEvent.getSource();

  //Find the client component for the "greeting" af:outputText
  var greetingComponent=buttonComponent.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を使用する必要があります。絶対識別子およびネーミング・コンテナ内のコンポーネントの検索の詳細は、次の項を参照してください。


注意:

似たような名前のAdfPage.PAGE.findComponent(clientId)というメソッドもありますが、この関数は、リリース間で変わる可能性のある実装固有の識別子を使用し、ページ作成者は使用しません。

3.5.1 ネーミング・コンテナ内のコンポーネントの検索について

見つける必要があるコンポーネントがネーミング・コンテナ(pageTemplatesubformtableおよびtreeなど)であるコンポーネントにある場合は、AdfPage.PAGE.findComponentByAbsoluteId(absolute expr)メソッドを使用するかわりに、AdfUIComponent.findComponent(expr)メソッドを使用します。絶対式も相対式も使用できます。


ヒント:

コンポーネントがネーミング・コンテナかどうかは、コンポーネント・タグのドキュメントを確認して判断できます。タグのドキュメントには、コンポーネントがネーミング・コンテナかどうかが示されています。

絶対式では、NamingContainer.SEPARATOR_CHAR文字を先頭とし、完全修飾されたJSFクライアントID(コンポーネントを含むNamingContainerコンポーネントのすべてのIDが先頭に付けられる)を使用します。次に例を示します。

":" + (namingContainersToJumpUp * ":") + some ending portion of the clientIdOfComponentToFind

たとえば、テンプレートを使用するページのリージョンに含まれるpanelCollectionコンポーネント内にある表を検索するには、次を使用します。

:someTemplate:someRegion:somePanelCollection:someTable

また、両方のコンポーネント(検索する側とされる側)が階層内で同じNamingContainerコンポーネントを共有する場合、相対パスを使用して、検索元のコンポーネントを基準とする検索を行えます。相対パスには、複数のNamingContainer.SEPARATOR_CHAR文字を先頭に含めることができます。次に例を示します。

":" + clientIdOfComponentToFind

前述の例で、検索元のコンポーネントが表と同じリージョンにある場合、次を使用できます。

::somePanelCollection:someTable

ヒント:

ネーミング・コンテナはフォルダ、clientIdはファイル・パスと考えることができます。フォルダとファイルの場合、連続する2つのピリオドとスラッシュ(../)を使用して階層の上位のフォルダに移動します。これは、複数のコロン(:)文字のfindComponent()式での動きと同じです。先頭の1つのコロン(:)は、ファイル・パスがファイル構造のルートからの絶対パスであることを示します。複数のコロン(:)文字が式の最初にある場合、最初のコロンは無視されます。残りのコロンは、各コロン(:)文字がピリオドとスラッシュの1つのセット(../)とみなされます。

絶対パスを使用するか相対パスを使用するかを決める際、次の点に注意します。

  • 検索対象のコンポーネントが常に同じネーミング・コンテナ内あることがわかっている場合は、絶対パスを使用します。

  • 検索元のコンポーネントと検索対象のコンポーネントの相対的位置が常に同じであることがわかっている場合は、相対パスを使用します。

クライアントにはgetChildren()関数もgetFacet()関数もありません。かわりに、すべての子コンポーネントとファセット(つまり、すべての子孫)にアクセスするAdfUIComponent.visitChildren()関数が用意されています。詳細は、ADF Faces JavaScriptのドキュメントを参照してください。

3.6 クライアントでのコンポーネント・プロパティへのアクセス

コンポーネントの各組込みプロパティには、簡易アクセッサ・メソッドがコンポーネント・クラスに用意されています。たとえば、クライアント・コンポーネントでgetValue()メソッドをコールし、サーバーで使用されたのと同じ値を受け取ることができます。


注意:

ブール・プロパティを含むすべてのプロパティでgetXyz関数ネーミング規則を使用します。JavaScriptのブール・プロパティのisXyzネーミング規則は使用されません。

定数もクラス・オブジェクトのプロパティ名に使用できます。たとえば、styleClassを使用するかわりにAdfRichDialog.STYLE_CLASS定数を使用できます。


注意:

文字列のコーディングは各起動時にオブジェクトの割当てが必要なため、JavaScriptでは定数を参照する方が効率的です。

コンポーネントのプロパティが変更されると、新しい状態が反映されるようコンポーネントのDOMが最終的に更新されます。サーバーへのラウンドトリップがない場合もあります。この処理でのコンポーネントの役割は非常に限られています。新しいプロパティ値を格納し、ピアに変更を通知するのみです。ピアには、コンポーネントの新しい状態を反映するようDOMを更新するロジックが含まれています。


注意:

すべてのプロパティの変更が、クライアント側のピアを使用して処理されるわけではありません。一部のプロパティ変更はサーバーに伝播され、PPRを使用してコンポーネントがレンダリングされます。

3.6.1 クライアントでのプロパティ値の設定方法

RCFには、AdfUIComponentsetProperty()関数をコールするためのsetXYZ簡易関数が用意されています。setProperty()関数は次の引数をとります。

  • プロパティ名(必須)

  • 新しい値(必須)

3.6.2 実行時の処理: クライアント・プロパティのクライアントでの設定方法

クライアントでsetProperty()関数をコールすると、プロパティが新しい値に設定され、値が変更された場合は、同時にPropertyChangeEventイベントが新しい値を使用して起動されます。また、プロパティを設定すると、コンポーネントが自身を再レンダリングする場合があります。

3.6.3 セキュア・プロパティと分離プロパティについて

1.2.2項「ADF Facesのアーキテクチャ上の機能」での説明のとおり、大半のプロパティ値はクライアントで設定されると、サーバーで設定されたように処理され、サーバーと自動的に同期がとられます(クライアントにまったく送信されない複雑なJavaオブジェクトもあります)。これとは異なる動作をするセキュア・プロパティと分離プロパティの2種類のプロパティもあります。

セキュア・プロパティは、クライアントで設定できないプロパティです。たとえば、悪意のあるクライアントでJavaScriptを使用してcommandLinkコンポーネントのimmediateフラグがtrueに設定されるとします。この変更がサーバーに伝播された結果、サーバー側の検証が省略され、セキュリティ・ホールとなる可能性があります(immediateプロパティの使用の詳細は、4.3項「immediate属性の使用」を参照してください)。つまり、immediateプロパティはセキュア・プロパティです。JavaScriptからセキュア・プロパティの設定を試みると失敗します。

分離プロパティは、クライアントで設定できるが、サーバーに伝播されないプロパティです。これは、プロパティで、サーバーでのライフサイクルに依存しないライフサイクルがクライアントにある場合に使用されます。たとえば、クライアント・フォーム入力コンポーネント(AdfRichInputTextなど)には、JavaのEditableValueHolderコンポーネントのようにsubmittedValueプロパティがあります。ただし、このプロパティの設定はサーバーに直接影響しません。この場合、標準のフォーム送信手法によって、送信された値のサーバーでの更新を処理します。

プロパティは、分離プロパティとセキュア・プロパティの両方にできます。実際には、これらはクライアントでは分離プロパティのように機能します。クライアントで設定できますが、サーバーに送信されません。しかし、サーバーでは、クライアントからの設定を受け付けないという点でセキュア・プロパティのように機能します。

3.7 クライアント側コンポーネントに対するボーナス属性の使用

組込みプロパティ以外の情報をクライアントに送信する必要がある場合もあります。これは、ボーナス属性を使用して行えます。ボーナス属性は、clientAttributeタグを使用してコンポーネントに追加できる追加属性です。パフォーマンス上の理由から、クライアントに送信されるボーナス属性は、clientAttributeで指定されたもののみです。

clientAttributeタグで、サーバー側コンポーネントの属性マップに追加される名前と値のペアを指定します。clientAttributeタグを使用すると、サーバー側属性マップへの移入に加え、ボーナス属性のクライアントへの送信も行われます。クライアントではAdfUIComponent.getProperty("bonusAttributeName")メソッドを使用してアクセスできます。

RCFで、属性値のクライアントへのマーシャリングが行われます。マーシャリング・レイヤーで、文字列、ブール、数値、日付、配列、マップなど、各オブジェクト型のマーシャリングがサポートされます。マーシャリングの詳細は、5.4.3項「データのマーシャリングとアンマーシャリングについて」を参照してください。


パフォーマンスの注意:

マーシャリングによる過度のオーバーヘッドを防ぐため、クライアント側ボーナス属性を多用しないでください。


注意:

clientAttributeタグは、(アプリケーションで定義される)ボーナス属性にのみ使用します。クライアントで標準のコンポーネント属性にアクセスする必要がある場合、clientAttributeタグを使用するのではなく、clientComponent属性をtrueに設定します。詳細は、3.4項「クライアント側コンポーネントのインスタンス化」を参照してください。

3.7.1 ボーナス属性の作成方法

コンポーネント・パレットを使用して、ボーナス属性をコンポーネントに追加できます。

ボーナス属性を作成する手順:

  1. JDeveloperでボーナス属性を追加するコンポーネントを選択します。

  2. コンポーネント・パレットの「操作」セクションで、クライアント属性をコンポーネントの子としてドラッグ・アンド・ドロップします。

  3. プロパティ・インスペクタで「名前」「値」属性を設定します。

3.7.2 ボーナス属性のマーシャリングについて

クライアント側ボーナス属性は、サーバーからクライアントへ自動的に配信されますが、その逆は行われません。つまり、クライアントでのボーナス属性の変更または設定は、サーバーに反映されません。既知(ボーナス以外)の属性のみ、クライアントからサーバーへ同期がとられます。アプリケーションで定義されたデータをサーバーに送り返す必要がある場合、カスタム・イベントを作成します。詳細は、5.4項「クライアントからサーバーへのカスタム・イベントの送信」を参照してください。

3.8 レンダリングおよび可視性の理解

すべてのADF Faces表示コンポーネントには、コンポーネントをページに表示してユーザーに見えるようにするかどうかに関係するrenderedvisibleの2つの属性があります。

rendered属性のセマンティクは非常に厳密です。renderedfalseに設定されている場合、サーバーへのラウンドトリップなしにコンポーネントをクライアントで表示することはできません。ページのコンテンツの動的な表示/非表示をサポートするために、RCFにはvisible属性が追加されています。falseに設定されている場合、コンポーネントのマークアップはクライアントで使用可能ですが、コンポーネントは表示されません。したがって、setVisible(true)またはsetVisible(false)メソッドをコールすると、JavaからのコールであろうとJavaScriptからのコールであろうと、コンポーネントがブラウザ内で表示または非表示になります(renderedtrueに設定されている場合)。


パフォーマンスのヒント:

JavaScriptなど、サーバーへのラウンドトリップなしに可視性を切り替える必要がある場合にのみvisible属性をfalseに設定します。非表示のコンポーネントも、検証を含むコンポーネント・ライフサイクルを経過します。

クライアントでのみ可視性を切り替える必要がない場合、rendered属性をfalseに設定します。コンポーネントをレンダリングしない(表示しないのではなく)場合、コンポーネントはクライアント側表現を持たず、コンポーネント・ライフサイクルを経過しないため、サーバーのパフォーマンスとクライアントのレスポンス時間が向上します。


例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と同じ機能で、rendered属性(rendered属性はデフォルトでtrue。明示的に設定する必要はない)のかわりに、visible属性を使用して表示するコンポーネントを決める方法を示します。

例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)
    }

 }

3.8.1 Javascriptを使用した可視性の設定方法

コンポーネントのvisible属性を切り替えられる条件付きJavaScript関数を作成できます。

可視性を設定する手順:

  1. 可視性を切り替えるJavaScriptを作成します。例3-12に、値がない場合にoutputTextコンポーネントの可視性を有効にし、そうでない場合は別のoutputTextコンポーネントの可視性を有効にするスクリプトを示します。

  2. JavaScript関数に必要なコンポーネントごとに、プロパティ・インスペクタで拡張セクションを開き、ClientComponent属性をtrueに設定します。これによって、JavaScriptで使用されるクライアント・コンポーネントが作成されます。

  3. 可視性を切り替えるコンポーネントのvisible属性をfalseに設定します。

例3-13に、JavaScriptを使用した可視性の切替えに使用されるページ・コード全体を示します。

例3-13 JavaScriptでの可視性の切替え

<f:view>
<trh:script>
  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)
      }

  }
</trh:script>
<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>

3.8.2 VisibleとisShowing関数について

コンポーネントの親のvisible属性がfalseに設定されている場合、visible属性がtrueに設定されている子コンポーネントにisVisible関数が実行されると、子が表示されていなくてもtrueが返されます。たとえば、outputTextコンポーネントを子として含むpanelGroupLayoutコンポーネントがあり、panelGroupLayoutコンポーネントのvisible属性はfalseに設定され、outputTextコンポーネントのvisible属性はデフォルトのまま(true)とします。クライアントでは、panelGroupLayoutコンポーネントもoutputTextコンポーネントも表示されませんが、isVisible関数がoutputTextコンポーネントに実行されると、trueが返されます。

このため、RCFにはisShowing()関数が用意されています。この関数は、コンポーネントのvisible属性がfalseに設定されている場合、またはコンポーネントの親のvisiblefalseに設定されている場合、falseを返します。