Localizar componente por ID no JSF

Eu quero encontrar algum UIComponent do bean gerenciado pelo id que eu forneci.

Eu escrevi o seguinte código:

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

Eu defini um p:inputTextarea como:

 

Agora, se uma chamada para o método como getUIComponent("activityDescription") está retornando null , mas se eu chamá-lo como getUIComponent("adminTabView:activityForm:activityDescription") então eu posso obter a instância org.primefaces.component.inputtextarea.InputTextarea .

Existe alguma maneira de obter o componente com apenas o id ou seja, “activityDescription” não o id absoluto ou seja, “adminTabView: activityForm: activityDescription”?

Você pode usar o seguinte código:

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

Este código encontrará apenas o primeiro componente na tree com o id você passar. Você terá que fazer algo personalizado se houver dois componentes com o mesmo nome na tree (isso é possível se eles tiverem menos de dois contêineres de nomenclatura diferentes).

Talvez não seja possível. O FacesContext.getCurrentInstance().getViewRoot().findComponent(id) retorna apenas um UIComponent . O ViewRoot é construído como uma tree, portanto, se você tiver dois formulários na visualização, cada um com um componente com id="text" , eles terão seus componentes pai adicionados ao id para não entrarem em conflito. Se você colocar os dois componentes id="text" dentro do mesmo formulário, você terá java.lang.IllegalStateException lançada.

Se você quiser encontrar todos os componentes com o id pesquisado, você pode escrever um método que implementa:

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

Ou se você quiser encontrar a primeira ocorrência:

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

Eu tento este código e é uma ajuda:

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

obrigado

Basta colocar prependId="false" no seu formulário no qual esta textarea está.

Sim, em todos os componentes pais que são NamingContainers você precisa adicionar o atributo prependId="false" – ele funcionará com com certeza e deve funcionar em outros.
Se não for possível configurá-lo via atributo no arquivo .xhtml, você deve definir esse valor como programaticamente.

Sugestão após comentário do autor da pergunta:

Se não houver tal atributo nos componentes que você está usando, tente escrever o método find assim:

 private UIComponent findComponent(String id, UIComponent where) { if (where == null) { return null; } else if (where.getId().equals(id)) { return where; } else { List 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; } 

Em seguida, basta invocar

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

Isso ajudará?