web-dev-qa-db-ja.com

JSFは、immediate = trueを使用せずに必須検証をスキップします

複数のフォームがあり、必須フィールドとオプションフィールドがあります。

submitそのようなフォームには、必須属性の検証を実行する必要がありますが、これは正常に機能します。 キャンセルこのようなフォームには、属性immediate="true"上のp:commandbuttonリクエスト値の適用中にアクションを実行します-ここで説明するフェーズ: 特定のボタンがクリックされましたか?

ただし、大きなフォームの場合は、ユーザーに保存ボタンを提供して、後で続行できるようにします。

現在の状態を保存するだけのために、必須属性の検証も無視したいと思います。ただし、immediate="true"は機能しません。なぜなら、JSFライフサイクルが「UpdateModelValues」フェーズに決して到達しないため、saveメソッドsimpleは何も保存しないからです。 ( http://www.javacodegeeks.com/2012/01/jsf-and-immediate-attribute-command.html による)

だから、必要なチェックをバイパスするが、ライフサイクルの半分をスキップしない方法は?

41
dognose

各ボタンは、フォームのメンバーである限り、Param-List内にエントリを作成します。そのため、そのエントリの存在のチェックを「必須」パラメータに単純に適用しました。

<h:form id="form" prependId="true">
...
<p:inputText id="someId"
    required="#{param['form:save']==null}" ... />
...
<p:commandButton id="save" value="Save" />
<p:commandButton id="submit" value="Submit" />
<p:commandButton id="cancel" value="Cancel" immediate="true" />
</h:form>

[送信]をクリックすると、param['form:save']NULLであり、式がtrueに変換されるため、検証が実行されます。

[保存]をクリックすると、param['form:save']NOT NULL(ただし空!)、falseに解決されるため、検証は無視されます。 (または、JSFがfalseに評価される式beeingのために必須フィールドではないと考えているとしましょう)

64
dognose

ボタンをクリックしたときに検証をスキップする場合は、スキップしたいボタンにパラメーターを簡単に追加します。例:

<p:commandButton value="button1" action="#{bean.action()}" >
   <f:param name="skipValidator" value="true"/>
</p:commandButton>

次に、バリデーターでこのパラメーターを読み取り、trueの場合はスキップできます。

@FacesValidator("com.validators.MyValidator")
public class MyValidator implements Validator{

  public void validate(FacesContext ct, UIComponent co, Object obj) throws ValidatorException { 
    if(!continueValidation()){
      return;
    }
    // validation process
  }

protected boolean continueValidation() {
    String skipValidator= FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("skipValidator");
    if (skipValidator != null && skipValidator.equalsIgnoreCase("true")) {
      return false;
    }
    return true;
  } 
}
5
Juraj

これは素晴らしい質問であり、非常に役立つ回答です。このアプローチは、immediate="true"で多くの手間を省きます。

この情報を追加したいのですが(まだコメントすることはできません)。あなたのコード例ではJSF 2.以上(私を修正)が必要と思われます。私のようにJSF 1.1/1.2を使用することをめている場合は、次の変更/追加を検討してください。

<h:form id="form">
...
<p:inputText id="someId" required="#{!empty param['save']}" ... />
...
<p:commandButton id="save" value="Save" />
</h:form>
  • JSF 1.1には属性prependIdはありません
  • したがって、param [...]では、ボタンIDのみを指定する必要があります
  • あなたは構文="{true and ...}"を使用していますが、これは間違いかもしれません(#はありません)?
  • あなた自身の編集履歴からわかるように、「null or not null」ロジックはあまり直観的ではありません:)だから私はすぐに!empty ...バージョンが好きになりました。
4
SebastianH

他の人が提案したものに代わるものは、カスタムのBeanValidatorを使用することです。これは、たとえば、id saveのボタンをクリックした場合にフォームを検証します。検証を実行するために暗黙的に定義されていない他のボタンは検証されず、利用可能なデータを送信するだけです。ナイスでクリーンな完全な例を見つける here

1
Given Nyauyanga

私の場合、paramsにボタンのclientIdが見つかりませんでしたが、このparam['javax.faces.source'] = buttonClientIdリクエストマップ内。値は、クリックされたボタンのclientIdになります。

0
Shady Aziz

このような場合には skipValidators を使用します(すべての検証がスキップされると仮定します)。 omnifaces のコード

<h:form>
  <h:dataTable value="#{bean.items}" var="item">
    <h:column>
        <h:inputText value="#{item.value}" required="true" />
    </h:column>
  </h:dataTable>
  <h:commandButton value="add new row" action="#{bean.add}">
    <o:skipValidators />
  </h:commandButton>
  <h:commandButton value="save all data" action="#{bean.save}" />
  <h:messages />
</h:form>
0
dr0ps