Подтвердить что ты не робот

Найти компонент по ID в JSF

Я хочу найти UIComponent из управляемого bean идентификатором, который я предоставил.

Я написал следующий код:

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

Я определил a 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.

Есть ли способ получить компонент только с идентификатором i.e, "activityDescription", а не с абсолютным id, то есть "adminTabView: activityForm: activityDescription"?

4b9b3361

Ответ 1

Вы можете использовать следующий код:

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 != null 
                && component.getId() != null 
                && component.getId().equals(id)) {
                found[0] = component;
                return VisitResult.COMPLETE;
            }
            return VisitResult.ACCEPT;              
        }
    });

    return found[0];

}

Этот код найдет только первый компонент в дереве с id, который вы передадите. Вам придется сделать что-то нестандартное, если в дереве есть 2 компонента с одинаковыми именами (это возможно, если они находятся в двух разных контейнерах именования).

Ответ 2

Я пробую этот код, и он помогает:

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

Спасибо

Ответ 3

Возможно, это невозможно. Метод FacesContext.getCurrentInstance().getViewRoot().findComponent(id) возвращает только один UIComponent. ViewRoot построен как дерево, поэтому, если у вас есть две формы в представлении, каждая из которых имеет компонент с id="text", они будут иметь его родительские компоненты, добавленные в идентификатор, чтобы они не конфликтуют. Если вы поместите две компоненты id="text" в одну и ту же форму, вы получите java.lang.IllegalStateException.

Если вы хотите найти все компоненты с искомым идентификатором, вы можете написать метод, который реализует:

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

Ответ 4

Просто поместите prependId="false" в свою форму, в которой находится это текстовое поле.

Ответ 5

Да, во всех родительских компонентах, которые NamingContainers, вам нужно добавить атрибут prependId="false" - он будет работать в <h:form> точно и должен работать в других.
Если невозможно установить его через атрибут в файле .xhtml, вы должны установить такое значение программно.

Предложение после комментария автора вопроса:

Если в компонентах нет такого атрибута, который вы используете, попробуйте написать метод поиска следующим образом:

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());

Это поможет?