web-dev-qa-db-ja.com

JSFでIDでコンポーネントを検索

提供したIDでマネージドBeanからUIComponentを見つけたいです。

私は次のコードを書きました:

_private UIComponent getUIComponent(String id) {  
      return FacesContext.getCurrentInstance().getViewRoot().findComponent(id) ;  
}
_

_p:inputTextarea_を次のように定義しました:

_<p:inputTextarea id="activityDescription" value="#{adminController.activityDTO.activityDescription}" required="true" maxlength="120"
    autoResize="true" counter="counter" counterTemplate="{0} characters remaining." cols="80" rows="2" />
_

メソッドをgetUIComponent("activityDescription")として呼び出すと、nullを返しますが、getUIComponent("adminTabView:activityForm:activityDescription")として呼び出すと、_org.primefaces.component.inputtextarea.InputTextarea_インスタンスを取得できます。

絶対IDではなく「adminTabView:activityForm:activityDescription」ではなく、「activityDescription」というIDのみを持つコンポーネントを取得する方法はありますか?

46
Tapas Bose

次のコードを使用できます。

public UIComponent findComponent(final String id) {

    FacesContext context = FacesContext.getCurrentInstance(); 
    UIViewRoot root = context.getViewRoot();
    final UIComponent[] found = new UIComponent[1];

    root.visitTree(new FullVisitContext(context), new VisitCallback() {     
        @Override
        public VisitResult visit(VisitContext context, UIComponent component) {
            if(component.getId().equals(id)){
                found[0] = component;
                return VisitResult.COMPLETE;
            }
            return VisitResult.ACCEPT;              
        }
    });

    return found[0];

}

このコードは、idが渡されたツリーの最初のコンポーネントのみを検索します。ツリー内に同じ名前のコンポーネントが2つある場合は、何らかのカスタム処理を行う必要があります(これらが2つの異なる名前付けコンテナの下にある場合は可能です)。

44
Nerrve

私はこのコードを試してみましたが、それは助けです:

private static UIComponent getUIComponentOfId(UIComponent root, String id){
    if(root.getId().equals(id)){
        return root;
    }
    if(root.getChildCount() > 0){
        for(UIComponent subUiComponent : root.getChildren()){
                UIComponent returnComponent = getUIComponentOfId(subUiComponent, id);
                if(returnComponent != null){
                    return returnComponent;
            }
        }
    }
    return null;
}

ありがとう

2
Hazim

ただprependId="false"このテキストエリアがあるフォームに。

1
Darka

たぶんそれは不可能です。 FacesContext.getCurrentInstance().getViewRoot().findComponent(id)メソッドは、1つのUIComponentのみを返します。 ViewRootはツリーとして構築されるため、ビューに2つのフォームがあり、それぞれにid="text"を持つコンポーネントがある場合、idに親コンポーネントが追加されるため、競合しません。 2つのid="text"コンポーネントを同じフォーム内に配置すると、Java.lang.IllegalStateExceptionがスローされます。

検索されたIDを持つすべてのコンポーネントを検索する場合、以下を実装するメソッドを作成できます。

List<UIComponent> foundComponents = new ArrayList();
for(UIComponent component: FacesContext.getCurrentInstance().getViewRoot().getChildren()) {
    if(component.getId().contains("activityDescription")){
        foundComponents.add(component);
    }
}

または、最初の出現を検索する場合:

UIComponent foundComponent;
for(UIComponent component: FacesContext.getCurrentInstance().getViewRoot().getChildren()) {
    if(component.getId().contains("activityDescription")){
        foundComponent = component;
        break;
    }
}
1
kauedg

はい、NamingContainersであるすべての親コンポーネントでは、属性prependId="false"を追加する必要があります。これは<h:form>で機能し、他のコンポーネントでも機能するはずです。
。xhtmlファイルの属性を介して設定できない場合、そのような値をプログラムで設定する必要があります。

質問の著者のコメントの後の提案:

使用しているコンポーネントにそのような属性がない場合は、次のようなfindメソッドを記述してください。

private UIComponent findComponent(String id, UIComponent where) {
if (where == null) {
   return null;
}
else if (where.getId().equals(id)) {
   return where;
}
else {
   List<UIComponent> childrenList = where.getChildren();
   if (childrenList == null || childrenList.isEmpty()) {
      return null;
   }
   for (UIComponent child : childrenList) {
      UIComponent result = null;
      result = findComponent(id, child);
      if(result != null) {
         return result;
   }
   return null;
}   

次に呼び出す

UIComponent iamLookingFor = findComponent(myId, FacesContext.getCurrentInstance().getViewRoot());

それは役立ちますか?

0
emka86