Найти компонент по 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"?
Ответы
Ответ 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());
Это поможет?