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

前
 
次
 

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コード・ライブラリが非常に大きくなった場合、ライブラリを内容に応じて分割し、(テンプレートではなく)ページで必要な部分のみを含めることに注意してください。この方法で、ブラウザ・キャッシュが使用され、ページの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を呼び出すコンポーネントを右クリックし、componentの中に挿入」「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を呼び出すコンポーネントを右クリックし、componentの中に挿入」「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セットのピリオドとスラッシュ(../)が考慮されます。


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

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

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

クライアントには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.10項「テストの自動化」を参照してください。

  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を使用してボタンを有効および無効にする必要がある場合に役立ちます。unsecureプロパティをtrueに設定すると、disabledプロパティ(およびdisabledプロパティのみ)が保護されなくなります。

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

プロパティは、分離とセキュアの両方にすることができます。実際には、このようなプロパティはクライアント上で分離プロパティのように動作します。これらはクライアントで設定できますが、サーバーには送信されません。ただし、サーバーではセキュア・プロパティとして動作するため、クライアントがこれらを設定しようとすると拒否されます。

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

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

  • プロパティ名(必須)

  • 新しい値(必須)

3.7.2 無効化されたプロパティを非保護にする方法

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属性、あるいはその両方を編集できるようにする場合は、サーバーとのラウンドトリップが発生した場合と同じロジックがアプリケーションによって実行されるようにする必要があります。

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コンポーネントを示します。一度にその一方のみがレンダリングされます。最初の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を返します。