【问题标题】:Find component by type in JSF在 JSF 中按类型查找组件
【发布时间】:2015-04-18 11:52:19
【问题描述】:

我的问题与Get all hidden input fields in JSF dynamically 相关,但这与我想使用 JSF 而不是纯 HTML 不同,并假设我的 .xhtml 文件中有以下内容:

<h:inputHidden id="name1" value="SomeValue1"/>
<h:inputHidden id="name2" value="SomeValue2"/>

我开发了一个小代码,尝试动态获取所有h:inputHidden 标签并将它们的值打印到控制台,但问题是我无法弄清楚如何让所有东西都动态化。在我的代码中,如果我想迭代 uicomponents,我应该知道 id 的形式,如何迭代组件树中的所有 UIComponent? (我试过UIViewRoot#getChildren(),但我只得到了第一个孩子)。

这里是sn-p的代码:

// formId is the id of my form
List<UIComponent> components = FacesContext.getCurrentInstance().getViewRoot().findComponent("formId").getChildren();
// A List of UIComponent where I am adding my Hidden Inputs
List<UIComponent> hiddenComponents = new ArrayList<UIComponent>();

for (UIComponent component : components) {

    // using the hidden inputs type in JSF: HtmlInputHidden
    if (component instanceof HtmlInputHidden) {
        hiddenComponents.add(component);
    }

}

for (UIComponent component : hiddenComponents) {

    // Printing the hidden inputs values for demonstration purposes
    System.out.println(((HtmlInputHidden)component).getValue());

}

【问题讨论】:

    标签: jsf jsf-2 uicomponents


    【解决方案1】:

    您还需要迭代孩子的孩子,以及他们的孩子,等等。你看,它是一个组件tree

    这是一个实用方法的启动 sn-p,它使用 tail recursion 完成此操作:

    public static <C extends UIComponent> void findChildrenByType(UIComponent parent, List<C> found, Class<C> type) {
        for (UIComponent child : parent.getChildren()) {
            if (type.isAssignableFrom(child.getClass())) {
                found.add(type.cast(child));
            }
    
            findChildrenByType(child, found, type);
        }
    }
    

    你可以这样使用它:

    UIForm form = (UIForm) FacesContext.getCurrentInstance().getViewRoot().findComponent("formId");
    List<HtmlInputHidden> hiddenComponents = new ArrayList<>();
    findChildrenByType(form, hiddenComponents, HtmlInputHidden.class);
    
    for (HtmlInputHidden hidden : hiddenComponents) {
        System.out.println(hidden.getValue());
    }
    

    或者,更好的是,使用UIComponent#visitTree(),它使用visitor pattern。主要区别在于它还迭代了 &lt;ui:repeat&gt;&lt;h:dataTable&gt; 等迭代组件,并为每次迭代恢复子状态。否则,当您将 &lt;h:inputHidden&gt; 包含在此类组件中时,您最终将得不到任何价值。

    FacesContext context = FacesContext.getCurrentInstance();
    List<Object> hiddenComponentValues = new ArrayList<>();
    context.getViewRoot().findComponent("formId").visitTree(VisitContext.createVisitContext(context), new VisitCallback() {
        @Override
        public VisitResult visit(VisitContext visitContext, UIComponent component) {
            if (component instanceof HtmlInputHidden) {
                hiddenComponentValues.add(((HtmlInputHidden) component).getValue());
                return VisitResult.COMPLETE;
            } else {
                return VisitResult.ACCEPT;
            }
        }
    });
    
    for (Object hiddenComponentValue : hiddenComponentValues) {
        System.out.println(hiddenComponentValue);
    }
    

    另见:

    毕竟,最简单的方法是按照通常的方式将它们绑定到 bean 属性,如果需要的话,在 &lt;ui:repeat&gt; 中:

    <h:inputHidden id="name1" value="#{bean.name1}"/>
    <h:inputHidden id="name2" value="#{bean.name2}"/>
    

    【讨论】:

    • 所以我可以直接调用 UIViewRoot 上的findComponentsByType() 方法吗?万一我不知道表格ID?例如:findComponentsByType(context.getViewRoot(), hiddenComponents, HtmlInputHidden.class); 这是正确的吗?我们也可以对visitTree 做同样的事情吗?
    • 你可以这样做。无论如何,它也是UIComponent。请注意,我稍微重命名了方法/参数名称以提高自记录性。
    • 是的,我刚刚注意到,最后一个问题,很抱歉打扰您:UIComponent#visitTree() 我们也可以直接在context.getViewRoot() 上调用它吗?
    • UIViewRoot 一个UIComponent
    • 我想你忘了修改findChildrenByType函数中的findComponentsByType名称。
    猜你喜欢
    • 2012-12-31
    • 2015-07-15
    • 2016-10-09
    • 2015-12-06
    • 1970-01-01
    • 2014-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多