web-dev-qa-db-fra.com

Rechercher un composant par ID dans JSF

Je veux trouver un UIComponent à partir du bean géré par l'identifiant que j'ai fourni. 

J'ai écrit le code suivant:

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

J'ai défini un p:inputTextarea comme:

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

Maintenant, si un appel à la méthode en tant que getUIComponent("activityDescription"), il renvoie null, mais si je l'appelle en tant que getUIComponent("adminTabView:activityForm:activityDescription"), je peux obtenir l'instance org.primefaces.component.inputtextarea.InputTextarea

Existe-t-il un moyen d’obtenir le composant avec uniquement l’identifiant, c’est-à-dire "activityDescription" et non l’identifiant absolu, c’est-à-dire "adminTabView: activityForm: activityDescription"?

44
Tapas Bose

Vous pouvez utiliser le code suivant:

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];

}

Ce code ne trouvera que le premier composant de l'arborescence avec la variable id que vous transmettez. Vous devrez faire quelque chose de personnalisé s'il y a 2 composants portant le même nom dans l'arborescence (cela est possible s'ils se trouvent sous 2 conteneurs de dénomination différents).

40
Nerrve

J'essaie ce code, et c'est une aide:

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;
}

Merci

2
Hazim

Il suffit de mettre prependId="false" à votre formulaire dans lequel se trouve cette zone de texte.

1
Darka

Peut-être que ce n'est pas possible La méthode FacesContext.getCurrentInstance().getViewRoot().findComponent(id) ne renvoie qu'une UIComponent. ViewRoot est construit sous forme d'arborescence. Par conséquent, si vous avez deux formulaires dans la vue, chacun avec un composant avec id="text", ses composants parents seront ajoutés à l'id pour éviter tout conflit. Si vous mettez les deux composants id="text" dans le même formulaire, vous aurez jeté Java.lang.IllegalStateException.

Si vous voulez trouver tous les composants avec l'ID recherché, vous pouvez écrire une méthode qui implémente:

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

Ou si vous voulez trouver la première occurrence:

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

Oui, dans tous les composants parents qui sont NamingContainers, vous devez ajouter l'attribut prependId="false" - cela fonctionnera certainement dans <h:form> et devrait fonctionner dans les autres. 
S'il n'est pas possible de le définir via un attribut dans un fichier .xhtml, vous devez définir cette valeur par programme.

Suggestion après le commentaire de l'auteur de la question:

S'il n'y a pas un tel attribut dans les composants que vous utilisez, essayez d'écrire méthode find comme ceci:

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;
}   

Suivant juste invoquer

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

Ça va aider?

0
emka86