ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Application Development Framework Webユーザー・インタフェース開発者ガイド
11gリリース1 (11.1.1.7.0)
B52029-07
  目次へ移動
目次

前
 
次
 

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.9項「レンダリングおよび可視性の理解」で説明されている、コンポーネントをレンダリングするかどうか、あるいは非表示にするかどうかを決めるプロパティを設定します。

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

次の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(event)
  {
    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-3に太字で示すコードを追加して、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

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

    注意:

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


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

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

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

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

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

  1. documentタグの下に、例3-5に太字で示すコードを追加し、JavaScriptライブラリが含まれるディレクトリへの相対パスに/mySourceDirectoryを置き換えます。

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

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

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

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

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項「実行時の処理: クライアント側イベントの機能の仕方」を参照してください。

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

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


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

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


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でこれを見つけて使用できます。

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

イベントのソースではないクライアント・コンポーネントを検索する必要がある場合、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項「ネーミング・コンテナ内のコンポーネントの検索について」を参照してください。


注意:

似たような名前の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

たとえば、myTemplateテンプレートを使用するページで、IDがr1のリージョンに含まれ、IDがpc1のパネル・コレクション・コンポーネント内にあるIDがt1の表を検索するには、次を使用します。

:myTemplate:r1:pc1:t1

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

":" + clientIdOfComponentToFind

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

::somePanelCollection:someTable

ヒント:

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


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

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

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

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

3.6 ユーザーの現在位置の特定

ADF Facesでは、イベントに関して現在のコンテキスト・ページ情報を返すJavaScript APIが用意されています。AdfPage.prototype.getViewId()関数では、現在表示されているビューの識別子を返します。このIDは、ページ全体のレンダリングまたは部分ページ・ナビゲーションのいずれかが発生すると設定されます。AdfPage.prototype.getComponentsByType(componentType)関数は、指定したコンポーネント・タイプに一致するコンポーネント・インスタンスの配列を返します。

たとえば、アプリケーションにタブ付きのページが含まれており、各タブが複数のリージョンで構成されているとします。各リージョンには、ネストされた他のリージョンも含めることができます。APIを使用すると、例3-9に示すように、ページ全体のviewIdと、ページで現在レンダリングされている各リージョンに表示されているフラグメントのviewIdsの組合せとなる文字列の識別子を返すことができます。

3.6.1 ユーザーの現在位置の特定方法

クライアント側のリージョン・コンポーネントのviewID propertyを取得するには、web.xmlファイルのパラメータを設定して、ユーザー・アクティビティ監視機能を有効にする必要があります。次に、現在のページを構成するviewIdsの文字列表現をビルドするJavaScriptコードを作成します。

コンテキスト識別子を決定する手順:

  1. web.xmlファイルをダブルクリックします。

  2. ソース・エディタで、oracle.adf.view.faces.context.ENABLE_ADF_EXECUTION_CONTEXT_PROVIDERをtrueに設定します。

    このパラメータでは、ExecutionContextProviderサービス・プロバイダが有効であることがADF Facesに通知されます。このサービスでは、クライアント開始のリクエストのユーザー・アクティビティ情報を監視して集約します。

  3. oracle.adf.view.rich.automation.ENABLEDをtrueに設定します。

    このパラメータにより、すべてのコンポーネントでコンポーネントIDが設定されます。詳細は、A.2.3.11項「テストの自動化」を参照してください。

  4. 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;
    }
    

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

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


注意:

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


定数もクラス・オブジェクトのプロパティ名に使用できます。たとえば、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 セキュアなクライアント・プロパティ

コンポーネント セキュアなプロパティ

AdfRichChooseColor

colorData

AdfRichComboboxListOfValue

disabled

readOnly

AdfRichCommandButton

disabled

readOnly

blocking

AdfRichCommandImageLink

blocking

disabled

partialSubmit

AdfRichCommandLink

readOnly

AdfRichDialog

dialogListener

AdfRichDocument

failedConnectionText

AdfRichInputColor

disabled

readOnly

colorData

AdfRichInputDate

disabled

readOnly

valuePassThru

AdfRichInputFile

disabled

readOnly

AdfRichInputListOfValues

disabled

readOnly

AdfRichInputNumberSlider

disabled

readOnly

AdfRichInputNumberSplinBox

disabled

readOnly

maximum

minimum

stepSize

AdfRichInputRangeSlider

disabled

readOnly

AdfRichInputText

disabled

readOnly

secret

AdfRichPopUp

launchPopupListener

model

returnPopupListener

returnPopupDataListener

createPopupId

AdfRichUIQuery

conjunctionReadOnly

model

queryListener

queryOperationListener

AdfRichSelectBooleanCheckbox

disabled

readOnly

AdfRichSelectBooleanRadio

disabled

readOnly

AdfRichSelectManyCheckbox

disabled

readOnly

valuePassThru

AdfRichSelectManyChoice

disabled

readOnly

valuePassThru

AdfRichSelectManyListBox

disabled

readOnly

valuePassThru

AdfRichSelectManyShuttle

disabled

readOnly

valuePassThru

AdfRichSelectOneChoice

disabled

readOnly

valuePassThru

AdfRichSelectOneListBox

disabled

readOnly

valuePassThru

AdfRichSelectOneRadio

disabled

readOnly

valuePassThru

AdfRichSelectOrderShuttle

disabled

readOnly

valuePassThru

AdfRichUITable

filterModel

AdfRichTextEditor

disabled

readOnly

AdfUIChart

chartDrillDownListener

AdfUIColumn

sortProperty

AdfUICommand

actionExpression

returnListener

launchListener

immediate

AdfUIComponentRef

componentType

AdfUIEditableValueBase

immediate

valid

required

localValueSet

submittedValue

requiredMessageDetail

AdfUIMessage.js

for

AdfUINavigationLevel

level

AdfUINavigationTree

rowDisclosureListener

startLevel

immediate

AdfUIPage

rowDisclosureListener

immediate

AdfUIPoll

immediate

pollListener

AdfUIProgress

immediate

AdfUISelectBoolean

selected

AdfUISelectInput

actionExpression

returnListener

AdfUISelectRange

immediate

rangeChangeListener

AdfUIShowDetailBase

immediate

disclosureListener

AdfUISingleStep

selectedStep

maxStep

AdfUISubform

default

AdfUITableBase

rowDisclosureListener

selectionListener

immediate

sortListener

rangeChangeListener

showAll

AdfUITreeBase

immediate

rowDisclosureListener

selectionListener

focusRowKey

focusListener

AdfUITreeTable

rowsByDepth

rangeChangeListener

AdfUIValueBase

converter


ADF Facesでは、保護されなくなるなるように、disabledプロパティを構成できます。これは、JavaScriptを使用してdisableボタンを有効にする必要がある場合に便利です。unsecureプロパティをtrueに設定すると、disabledプロパティ(およびdisabledプロパティのみ)が保護されなくなります。

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

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

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

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

  • プロパティ名(必須)

  • 新しい値(必須)

3.7.2 disabledプロパティを保護しない方法

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属性(あるいはその両方)を潜在的に編集できるようにするには、サーバへのラウンドトリップが実行されるのと同様に、同じロジックをアプリケーションで実行する必要があります。

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

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

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

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

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

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


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

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



注意:

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


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

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

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

  1. 構造ウィンドウで、ボーナス属性を追加するコンポーネントを選択します。

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

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

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

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

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

すべての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と同じ機能を達成する方法を示しますが、この例では、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)
    }
    
 }
   

3.9.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>
<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>

3.9.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を返します。