valueChangeListenerまたはf:ajaxリスナーをいつ使用するのですか?


87

listener配置に関して、次の2つのコードの違いは何ですか?

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

そして

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

回答:


182

valueChangeListenerフォームが送信された場合にのみ呼び出されると、送信された値が初期値と異なっています。したがって、HTMLDOMイベントのみが発生した場合は呼び出されませんchange。HTML DOMchangeイベント中にフォームを送信する場合は<f:ajax/>、リスナー(!)なしで別のフォームを入力コンポーネントに追加する必要があります。これにより、現在のコンポーネントのみを処理するフォームが送信されます(のようにexecute="@this")。

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

<f:ajax listener>代わりにを使用するとvalueChangeListener、デフォルトでHTMLDOMchangeイベント中にすでに実行されます。UICommandチェックボックスまたはラジオボタンを表すコンポーネントおよび入力コンポーネントの内部では、デフォルトではHTMLDOMclickイベント中にのみ実行されます。

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

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

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

この<f:ajax listener>メソッドはINVOKE_APPLICATIONフェーズ中に呼び出されます。その時点で、送信された値はモデルですでに更新されています。入力コンポーネントのにバインドされているbeanプロパティに直接アクセスすることで取得できます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アプリケーション/チュートリアル/リソースで、avalueChangeListenerがそのような構成に含まれていることが、それと組み合わせて使用​​され、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
    // ...
}

@BalusC、渡された新しい値に設定する前に、セッターのバッキングオブジェクトから古い値を取得しない理由はありますか?このようなもの:。その方法で取得した新旧の値を使用して、セッターで直接ビジネスロジックを実行したり、単純なロギングを実行したりできるようですが、これが副作用を引き起こすかどうかはわかりません...logger.trace( "setting changeTypes from {} to {}", this.changeTypes, changeTypes );
Lucas

完璧で完全な答え!あなたの知識を共有してくれてありがとう!
hbobenicio 2015年

@BalusCは、AjaxBehaviorEventを介して変更された値を取得することもできますか?他のコンポーネントにチェーンされている<h:selectManyListboxがあり、変更された(追加/削除)を使用して何らかのアクションを実行したい
Paullo 2015


@BalusCに感謝しますが、<f:ajax event = "valueChange" render = "tests" execute = "@ this" listener = "#{testController。 processTimeTable} "/>
Paullo 2015

9

最初のフラグメント(ajaxリスナー属性)の場合:

ajaxタグの「listener」属性は、ajax関数がクライアント側で発生するたびにサーバー側で呼び出されるメソッドです。たとえば、この属性を使用して、ユーザーがキーを押すたびに呼び出すサーバー側関数を指定できます。

しかし、2番目のフラグメント(valueChangeListener):

ValueChangeListenerは、入力の値が変更されたときではなく、フォームが送信されたときにのみ呼び出されます

*あなたはこの便利な答えを見たいかもしれません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.