1

ポップアップに検証メッセージを表示するカスタムコンポーネントを作成していますが、それでも問題があります。検証メッセージにcliendIdsの代わりにコンポーネントラベルを表示したいのです。

私はすでにこの質問と同様のものを見ました:

JSFでメッセージバンドルを使用するときに検証メッセージからコンポーネントIDを削除する

labelしかし、jsf 1.1を使用していて、属性またはの値を設定しようとすると、コンパイルエラーが発生しますrequiredMessage<outputLabel />そこで、 :を使用してコンポーネントにラベルを割り当ててみました。

<h:outputLabel for="phone" value="Phone number" />
<h:inputText id="phone" required="true" value="#{backingBean.phoneNumber}" />

効果はありません。

jsf 1.1で、クライアントIDの代わりにラベルを検証メッセージに表示する簡単な方法はありますか?そうでない場合、コンポーネントを指定して、関連するラベルコンポーネントを取得し、Javaコードで作業を行うにはどうすればよいですか?

ありがとう。

4

3 に答える 3

2

既存の JSF コードを変更する必要のない解決策を見つけました。

  1. コンポーネント レンダラーHtmlMessagesRendererに、ID の代わりにコンポーネント ラベルを使用できる Tomahawk の を拡張させます。
  2. HtmlMessagesRenderer#findInputIdメッセージでコンポーネントの ID を取得するために使用します
  3. HtmlMessagesRenderer#findInputLabelメッセージを含むコンポーネントのラベルを取得するために使用します
  4. メッセージ内のコンポーネント ID をコンポーネント ラベルに置き換えます。

以下は、コンポーネントの RenderencodeBeginメソッドのコードからの抜粋です。このコードでは、2 つの別個のループを作成しました。最初はコンポーネント メッセージ用で、もう 1 つはグローバル メッセージ用です。

FacesContext#getClientIdsWithMessagesも返すことに注意してくださいnull。これは、グローバル メッセージの clientId と見なされます。

コンポーネント自体がコンポーネント ラベルを取得して使用するため、存在する場合は注意してください。<myCustomMessages />このソリューションでは、JSF ページ コードにタグを配置するだけで済みます。

public void encodeBegin(FacesContext context, UIComponent component) throws IOException {
// ....

// replace id with label in messages for components
        Iterator<String> clientIdsWithMessages=context.getClientIdsWithMessages();
        while(clientIdsWithMessages.hasNext()){
            String clientIdWithMessages=clientIdsWithMessages.next();
            if(clientIdWithMessages!=null){
                Iterator<FacesMessage> componentMessages=context.getMessages(clientIdWithMessages);
                while(componentMessages.hasNext()){
                    String stringMessage=componentMessages.next().getDetail();
                    try{
                        String inputId =findInputId(context, clientIdWithMessages);
                        String inputLabel = findInputLabel(context, clientIdWithMessages);
                        if(inputId!=null && inputLabel!=null)
                            stringMessage=stringMessage.replace(inputId, inputLabel);
                    } catch(Exception e){
                        // do nothing in this catch, just let the message be rendered with the componentId instead of a label                       }
                    msgBuilder.append(stringMessage);
                    msgBuilder.append("<br />");
                }
            }
        }


        // process global messages
        Iterator<FacesMessage> globalMessages=context.getMessages(null);
        while(globalMessages.hasNext()){
            FacesMessage message=globalMessages.next();
            msgBuilder.append(message.getDetail());
            msgBuilder.append("<br />");
        }
// ...

HtmlMessagesRenderer#findInputLabelこれがどのように機能するかを見るためのソースコードへの参照です。

于 2013-01-25T09:10:32.960 に答える
1

ひとつの解決策を考えます。beforePhase メソッド内でPhaseListener検索する new をPhaseEvent追加して、次のように記述できます。PhaseId = RENDER_RESPONSE

public class MyPhaseListener implements PhaseListener {

  private void findKeyValuePairInTree(UIComponent root, 
                                      Map<String, String> map) {
    if (root instanceof HtmlOutputLabel) {
      map.put(((HtmlOutputLabel) root).getFor(), 
                       ((HtmlOutputLabel) root).getValue());
    }
    if (root.getChilder() != null && !root.getChildren().isEmpty()) {
      for (UIComponent child : root.getChilder()) {
        findKeyValuePairInTree(child, map);
      }
    }

  private HashMap<String, String> idToLabelMap= new HashMap<String,String>();

  public void beforePhase(PhaseEvent event) {
    if (event.getPhaseId().equals(PhaseId.RENDER_RESPONSE) {

      findKeyValuePairInTree(FacesContext.getCurrentInstance().getViewRoot(),
                             idToLabelMap);
      // after above function finished execution in idToLabelMap will be all 
      // pairs of component ID used in standard FacesMessage as key
      // and HtmlOutputLabel value attr used as value
     
      Set<String> keySet = idToLabelMap.keySet();
      for(String key : keySet) {
        Iterator messages = FacesContext.getCurrentInstance().getMessages(key);
        while (iterator.hasNext) {
          FacesMessage msg = (FacesMessage) iterator.next();

          // now replace all occurences of clientId with label value from map

          msg.setSummary(msg.getSummary().replaceAll(key, idToLabelMap.get(key)));
          msg.setDetails(msg.getDetails().replaceAll(key, idToLabelMap.get(key)));
        }
      }
      FacesContext.getCurrentInstance().getMessages();
    } 
  }

...

}

このメソッドの後に来るレンダー フェーズでは、すべてのメッセージがラベル値でFacesContext.getCurrentInstance().getMessages()変更されclientIdます。検証フェーズはレンダー フェーズの前にあるため、すべての検証が成功または失敗します。検証からのメッセージはもうありません。

唯一の問題は、インスタンスのfor属性でHtmlOutputLabel同じ ID を 2 回以上使用する場合です。これは、異なるフォームで同じ ID がコンポーネントに使用される可能性があるためです。次に、forattr 内部<h:outputLabel>でより洗練された ID を使用できます。たとえば、フォーム ID などで手がかりを付けることができます。

于 2013-01-17T19:33:34.907 に答える
0
  1. 出力ラベルをバインドします。
  2. エラーメッセージをバインドします。
  3. javaから出力ラベルの値を設定します。
  4. 検証が失敗した場合は、検証をチェックして、出力ラベルの値を取得し、エラー メッセージ変数に設定します。
于 2013-01-17T09:47:59.787 に答える