- PR -

JSFのカスタムコンポーネントでボタンの作成方法に関して

1
投稿者投稿内容
sima
会議室デビュー日: 2006/07/09
投稿数: 2
投稿日時: 2006-09-04 00:05
現在、JSFを使用して開発を行っており、問題に直面しています。
標準のJSFタグではどうしても表現できない表をレンダーするためにカスタムコンポーネントを
使っています。このとき、カスタムコンポーネントのRendererクラスの
encodeEndメソッドで
(1)<h:commandButton value="go" type="submit" action="#{caveBean.doAction}"/>

(1)と同じ意味をもったhtmlをレンダーすることは可能なのでしょうか?

下記のソースのようにしてvalue属性やtype属性をレンダーすることはできたのですがaction属性をどのようにしたらよいのか解りませんでした。(標準タグで実際に(1)を記述しhtmlを見たのですがhiddenでsessionIDのような文字列を埋め込んでるようにしか見えず、どのようにaction属性をサーバに通達しているのか皆目不明でした)

public void encodeEnd(FacesContext context, UIComponent component) throws java.io.IOException
{

XYZComponent xYZComponent = (XYZComponent)component;
ResponseWriter writer = context.getResponseWriter();
String clientId = component.getClientId(context);
writer.startElement("input", component);
writer.writeAttribute("type", "submit", null);
writer.writeAttribute("id", clientId, null);
writer.writeAttribute("name", clientId, null);
writer.writeAttribute("value", "go", null);
writer.endElement("input");

}



それともJSFではカスタムコンポーネントでボタンをレンダーするのはそもそも推奨していないのでしょうか?有識者の方アドバイスを宜しくお願いします。


よしだひろゆき
大ベテラン
会議室デビュー日: 2004/11/22
投稿数: 141
投稿日時: 2006-09-04 09:31
カスタムコンポーネントを作ろうというからには、フレームワークとしてのJSFの基本動作をもう少し理解する必要がありそうですね。

JSFはサーバ側にコンポーネントツリーを保持し、ブラウザからのイベントをツリー上のコンポーネントにブロードキャストすることで処理を進めます。

ボタンについて言えば、actionを実行するのは当然サーバ側であり、ブラウザからはそのボタンがクリックされたというイベントだけが到着するようにレンダリングします。つまりaction属性はサーバ側に保持するだけで、レンダリングする必要がありません。

逆に言えば、カスタムコンポーネントにボタンの機能を持たせるためには、
(1) コンポーネントがアクションイベントを処理するようにする
(2) レンダラのencodeBeginで、クリックされた時に適切なリクエストパラメタを送り出すようにする
(3) レンダラのdecodeで、(2)のリクエストパラメタに対応してアクションイベントをキューイングする
という仕掛けが必要です。
よしだひろゆき
大ベテラン
会議室デビュー日: 2004/11/22
投稿数: 141
投稿日時: 2006-09-05 14:38
引用:

カスタムコンポーネントにボタンの機能を持たせるためには、
(1) コンポーネントがアクションイベントを処理するようにする
(2) レンダラのencodeBeginで、クリックされた時に適切なリクエストパラメタを送り出すようにする
(3) レンダラのdecodeで、(2)のリクエストパラメタに対応してアクションイベントをキューイングする
という仕掛けが必要です。


ちょっとそっけなかったかなぁと反省して。

標準のコマンドボタンの場合を説明します。カスタムコンポーネントでも同じように動作させる必要があります。

・Render Response Phaseでjspの実行時の処理
タグハンドラ.doStartTag()
→タグハンドラ.setProperties()
 action属性のStringをMethodBindingに変換して、コンポーネント.setAction()
→コンポーネント.encodeBegin()
 →レンダラ.encodeBegin() // コンポーネント.encodeBeginのデフォルト処理
  →<input type="submit" name="クライアントID" value="OK"/>をレンダリング

・ブラウザ上でOKボタンをクリックすると、クライアントID=OK というパラメタを含んだhttpリクエストを送信

・Apply Request Values Phaseでのコンポーネントツリー処理
コンポーネント.processDecode()
→コンポーネント.decode()
 →レンダラ.decode() // デフォルト処理
  →名前がクライアントIDと等しいリクエストパラメタがあればActionEventをnewして、コンポーネント.queueEvent()

・Invoke Application Phaseでのイベント処理
アクションイベント.getComponent()でイベントの対象コンポーネントを取得して、コンポーネント.broadcast()
→デフォルトActionListener.processAction()
 コンポーネント.getAction()でアクション属性(メソッドバインディング)を取得して、
 メソッドバインディング.invoke()、
 その結果(outcome)を引数にデフォルトNavigationHandler.handleNavigation()をcall

タグハンドラ/カスタムコンポーネント/カスタムレンダラで実際にコーディングしなければならないのは、setProperties、setAction、getAction、encodeBegin、decodeあたりです。上記に出現するそれ以外のメソッドは、スーパークラスを適切に選択すれば継承だけで済みます。もし継承したメソッドだけで処理が不足する場合には、super.xxxx()のようにしてスーパークラスのデフォルト処理を呼び出した上で、必要な処理を追加したものでオーバーライドします。
1

スキルアップ/キャリアアップ(JOB@IT)