1. ホーム
  2. ajax

[解決済み] valueChangeListenerとf:ajaxリスナーのどちらを使うべきか?

2023-04-07 02:28:59

質問

次の二つのコードの違いは何でしょうか? listener の配置に関して、どのような違いがあるのでしょうか?

<h:selectOneMenu ...>
    <f:selectItems ... />
    <f:ajax listener="#{bean.listener}" />
</h:selectOneMenu>

<h:selectOneMenu ... valueChangeListener="#{bean.listener}">
    <f:selectItems ... />
</h:selectOneMenu>

どのように解決するのですか?

この valueChangeListener は、フォームが送信されたときにのみ呼び出されます。 の場合、送信された値は初期値とは異なります。したがって のみ の場合、HTML DOM change イベントが発生します。フォームを送信したい場合は、HTML DOMの change イベントの間にフォームを送信したい場合は、別の <f:ajax/> を追加する必要があります。これは、現在のコンポーネントのみを処理するフォーム送信を引き起こします (たとえば execute="@this" ).

<h:selectOneMenu value="#{bean.value}" valueChangeListener="#{bean.changeListener}">
    <f:selectItems ... />
    <f:ajax />
</h:selectOneMenu>


を使用する場合 <f:ajax listener> の代わりに valueChangeListener の代わりに、HTML DOM の中でデフォルトで実行されます。 change イベント中に実行されます。内部では UICommand コンポーネントや、チェックボックスやラジオボタンを表す入力コンポーネントの内部では、デフォルトで HTML DOM の click イベント時にのみ実行されます。

<h:selectOneMenu value="#{bean.value}">
    <f:selectItems ... />
    <f:ajax listener="#{bean.ajaxListener}" />
</h:selectOneMenu>


もう一つの大きな違いは valueChangeListener メソッドの終了時に呼び出されることです。 PROCESS_VALIDATIONS フェーズの終了時に呼び出されます。その時点では、投稿された値はまだモデル内で更新されていません。従って、入力コンポーネントにバインドされたビーンプロパティにアクセスするだけでは、その値を取得することはできません。 value . によって取得する必要があります。 ValueChangeEvent#getNewValue() . ちなみに、古い値も ValueChangeEvent#getOldValue() .

public void changeListener(ValueChangeEvent event) {
    Object oldValue = event.getOldValue();
    Object newValue = event.getNewValue();
    // ...
}


<f:ajax listener> メソッドが呼び出されるのは INVOKE_APPLICATION フェーズで呼び出されます。このとき、投稿された値はすでにモデル内で更新されています。入力コンポーネントにバインドされたビーンプロパティに直接アクセスすることで、それを取得することができます。 value .

private Object value; // +getter+setter.

public void ajaxListener(AjaxBehaviorEvent event) {
    System.out.println(value); // Look, (new) value is already set.
}


また、もし更新が必要なら 別の プロパティを更新する必要がある場合、それは valueChangeListener を更新されたプロパティとして ができます。 の間に提出された値によって上書きされます。 UPDATE_MODEL_VALUES フェーズで送信された値によって上書きされます。これはまさに、古い JSF 1.x のアプリケーション/チュートリアル/リソースで valueChangeListener がこのような構成で immediate="true"FacesContext#renderResponse() を使って、それを防いでいます。結局のところ valueChangeListener を使用してビジネスアクションを実行することは、実際には常にハック/回避策なのです。

要約すると このような場合 valueChangeListener を使うのは、実際の値の変化そのものを傍受する必要がある場合だけです。つまり、あなたが実際に興味を持っているのは に興味がある場合です(例えば、ログを取るため)。

public void changeListener(ValueChangeEvent event) {
    changeLogger.log(event.getOldValue(), event.getNewValue());
}

を使用します。 <f:ajax listener> を使うのは、新しく変更された値に対してビジネスアクションを実行する必要がある場合だけです。つまり、あなたが実際に興味を持っているのは だけです。 にしか興味がない場合です (たとえば、2 番目のドロップダウンにデータを入力する場合など)。

public void ajaxListener(AjaxBehaviorEvent event) {
    selectItemsOfSecondDropdown = populateItBasedOn(selectedValueOfFirstDropdown);
}

ビジネス・アクションの実行中に、実は古い値にも興味があるのなら、フォールバックして valueChangeListener に戻りますが、キューに入れるのは INVOKE_APPLICATION フェーズに待ちます。

public void changeListener(ValueChangeEvent event) {
    if (event.getPhaseId() != PhaseId.INVOKE_APPLICATION) {
        event.setPhaseId(PhaseId.INVOKE_APPLICATION);
        event.queue();
        return;
    }

    Object oldValue = event.getOldValue();
    Object newValue = event.getNewValue();
    System.out.println(newValue.equals(value)); // true
    // ...
}