1

私は得た

j_idt7:city: 検証エラー: 値が無効です

チーズにカット、ManagedBean コード:

 //few imports here
 @ManagedBean
 @SessionScoped
 public class CountriesAndCities implements Serializable{
 private List<SelectItem> countries;
 private List<SelectItem> cities;
 private  Map<String,List> m;
 private String selectedCountry;

 public String getSelectedCountry() {
return selectedCountry;
 }

 public void setSelectedCountry(String selectedCountry) {
this.selectedCountry = selectedCountry;
 }

 public CountriesAndCities(){
countries = new ArrayList<SelectItem>();
cities = new ArrayList<SelectItem>();
m = new HashMap<String,List>();
m.put("France", Arrays.asList("paris","marseille"));
m.put("England", Arrays.asList("Munchester","liverpoor"));

 }

 public  List<SelectItem> getCountries(){   
cities.removeAll(cities);
countries.removeAll(countries); 
countries.add(new SelectItem("select country"));
for(Map.Entry<String, List> entry: m.entrySet()){
    countries.add(new SelectItem(entry.getKey()));
    }

return countries;
 }
 public List<SelectItem> getCities(){   
for(Map.Entry<String, List> entry: m.entrySet())
      {if(entry.getKey().toString().equals(selectedCountry)){
        cities.addAll(entry.getValue());
        break;
    }
}
return cities;
 }
 public void checkSelectedCountry(ValueChangeEvent event){
selectedCountry = event.getNewValue().toString();   
 }

これが私の .xhtml のスニペットです:

 <h:selectOneMenu immediate="true" value="#{countriesAndCities.selectedCountry}" 
 onchange="submit()" valueChangeListener="#{countriesAndCities.checkSelectedCountry}">
 <f:selectItems value="#{countriesAndCities.countries}"></f:selectItems>
 </h:selectOneMenu>
 <br/>
 <h:selectOneMenu id="city">
 <f:selectItems value="#{countriesAndCities.cities}"></f:selectItems>
 </h:selectOneMenu>     
 </h:form>

コードは本来あるべきことを行いますが、最初の行で上記のエラーが発生します。イングランドをクリックして国の選択を選択した場合のみです。理由はわかりません。同じタスクをAjax化されたコードで記述しましたが、うまくいきました、どんな手でもありがたいです。

4

3 に答える 3

3

選択したアイテムのテストがリスト内の使用可能なアイテムのいずれにも返されなかった場合、エラーValidation Error: Value is not validがスローされます。したがって、基本的には次の2つの原因があります。equals()true

  1. equals()項目値タイプのメソッドが欠落しているか壊れています。
  2. 送信中に利用可能なアイテムのリストが変更され、互換性がなくなりました。

アイテムの値の型はStringであるため、そのequals()メソッドは間違いなく適切に実装されています (そうしないと、Java の世界ではすべてが壊れてしまいます)。したがって、原因 1 は傷が付く可能性があります。原因 2 が残っています。はい、確かに、不明な理由で、countries のゲッターで利用可能な都市のリストを空にしています。

public List<SelectItem> getCountries() {   
    cities.removeAll(cities);
    // ...
}

このコードは意味がありません。ゲッターは、選択した国が検証されるときにも呼び出されます。このようにして、後で検証しようとしているときに、選択した都市が利用可能な都市のリストに表示されません。ちなみに、あなたgetCities()も意味がありません。を使用するだけでなく、マップ全体をループしていますMap#get()

これはすべて、壊れたコード設計です。ゲッターには、ビジネス ロジックを一切含めないでください。ゲッターは、Bean プロパティのみを返す必要があります。これらの Bean プロパティは、(ポスト) コンストラクターまたはアクション (リスナー) メソッドでかなり前に事前に初期化されている必要があります。

これを修正する方法は、適切な 2 番目の問題です。は<h:selectOneMenu valueChangeListener>基本的にここで悪用されます。それは仕事には不適切なツールです。<f:ajax listener>代わりにこれを使用する必要があります。しかし、あなたが本当にvalueChangeListener仕事のために悪用を主張するなら、次のようにそれを解決すべきでした。それにより、ValueChangeEventtoINVOKE_APPLICATIONフェーズをキューに入れ、そのフェーズ中にジョブを実行します ((ajax) アクションリスナーメソッドであるかのように):

private List<String> countries;
private List<String> cities;
private Map<String, List<String>> countriesAndCities;
private String selectedCountry;

@PostConstruct
public void init() {
    countriesAndCities = new LinkedHashMap<String, List<String>>(); // Note: LinkedHashMap remembers insertion order, HashMap not.
    countriesAndCities.put("France", Arrays.asList("paris","marseille"));
    countriesAndCities.put("England", Arrays.asList("Munchester","liverpoor"));
    countries = new ArrayList<String>(countriesAndCities.keySet());
}

public void checkSelectedCountry(ValueChangeEvent event) { // I'd rename that method name to loadCities() or something more sensible.
    if (event.getPhaseId() != PhaseId.INVOKE_APPPLICATION) {
        // Move the job to the INVOKE_APPLICATION phase. 
        // The PROCESS_VALIDATIONS phase is the wrong phase for the "action listener"-like job.
        event.setPhaseId(PhaseId.INVOKE_APPLICATION);
        event.queue();
        return;
    }

    cities = countriesAndCities.get(selectedCountry);
}

// Getters and setters. Do not change them! They should just get and set properties. Nothing more!

public List<String> getCountries(){   
    return countries;
}

public List<String> getCities(){   
    return cities;
}

public String getSelectedCountry() {
    return selectedCountry;
}

public void setSelectedCountry(String selectedCountry) {
    this.selectedCountry = selectedCountry;
}

何らかのフォーム検証がある場合、これは依然として潜在的な問題を引き起こすことに注意してください。より良い解決策は、<f:ajax>代わりに使用することです。

以下も参照してください。

于 2012-12-04T18:44:27.180 に答える
1

取り除くimmediate="true"onchange="submit()"

追加

<f:ajax render="city"/>

あなたの最初の中に<h:selectOneMenu

このような

<h:selectOneMenu  value="#{countriesAndCities.selectedCountry}" valueChangeListener="#{countriesAndCities.checkSelectedCountry}">
     <f:selectItems value="#{countriesAndCities.countries}"></f:selectItems>
     <f:ajax render="city"/>
</h:selectOneMenu>

このLearning JSF2: Ajax in JSF – using f:ajax タグを読んでください

于 2012-12-04T15:38:08.540 に答える
1

ゲッターでの処理を減らすことをお勧めします(読み取り:処理なし)。何らかの理由で、コンポーネントにバインドされたデータソースのコンテンツがリクエストの途中で変更された場合、JSF は検証エラーをスローします (ソフト セキュリティ機能として)。これらのリストのポピュレーションをライフサイクル フック ( で注釈が付けられた public void no-args メソッド@PostConstruct) に移動します。これは、Bean がコンテキストによってインスタンス化された直後に実行されます。

ajax (悪い設計) のために、セッションスコープの Bean でビューをサポートしていると思います。その Bean を に変更し@ViewScopedて、デザインを滑らかにし、Ajax 処理を楽しんでください。

于 2012-12-04T16:50:44.843 に答える