gpt4 book ai didi

jsf-2 - 如何将支持 bean 中的 FacesMessage 附加到 ui :repeat? 中的特定字段

转载 作者:行者123 更新时间:2023-12-02 01:57:34 24 4
gpt4 key购买 nike

我有一个包含可变数量输入元素的表单,如下所示:

<ui:repeat var="_lang" value="#{myBean.languages}">
<h:inputTextarea value="${_lang.title}" id="theTitle" />
<h:messages for="theTitle"/>
</ui:repeat>

当支持 bean 中的某个方法被触发时,我想向 ui:repeat 的第二次迭代添加一条消息。 , 但不是其他的。

我看过 different variations of this question around here ,所有问题似乎都是由于 ui:repeat 引起的的迭代在 JSF 组件树中不可用。

到目前为止我尝试了什么:

  • 绑定(bind) h:inputTextarea s 到 Map<String,UIComponent>在 bean 里。 (a) ...使用 ...binding="#{myBean.uiMap[_lang.id]}" (其中 _lang.id 是一个唯一的字符串)。这产生了JBWEB006017: Target Unreachable, ''BracketSuffix'' returned null。 (我使用 id 转储了相应的字符串映射,相同的语法在 binding 之外工作得很好)(b)...或使用 ...binding="#{myBean.uiMap.get()}" .这使页面正常,但是当我为我的方法按下按钮时,不会调用 setter,因此 UIComponent永远不会添加到 Map .

  • 绑定(bind) h:inputTextarea s 到数组 UIComponent[]在 bean 中,用正确数量的空值预填充它,然后使用 ui:repeat 的行计数器作为 xhtml 文件中的索引。出现空指针异常,从未调用数组的 setter ,因此从未使用实际的 UIComponent 填充数组

  • 绑定(bind)外层h:panelGroup到 bean 并尝试在 JSF 树中的子项中递归地查找输入元素。仅找到一个输入,请参阅上面的“迭代不可用”问题。

  • 我也尝试替换 ui:repeatc:forEach并手动生成行号(以便它们有望在 JSF 树中可用),但我根本没有得到任何渲染输出。

(注意:目标是显示验证错误消息,但它们必须来自支持 bean。使用 f:validator 或类似的,甚至是自定义的,并不是真正的选择,因为我需要验证支持 bean 中的数据。)

坦率地说,我没有想法。这不会那么困难吧?

编辑:

第三次尝试,绑定(bind)到外部 h:panelGroup ,这是我的 JSF 查找器函数:

private List<UIComponent> findTitleComponents(UIComponent node) {
List<UIComponent> found = new ArrayList<UIComponent>();
for (UIComponent child : node.getChildren()) {
if (child.getId().equals("theTitle")) {
found.add(child);
log.debug("have found "+child.getClientId());
} else {
found.addAll(findTitleComponents(child));
log.debug("recursion into "+child.getClientId());
}
}
return found;
}

我调用 node ,这是绑定(bind) UIComponenth:panelGroup ui:repeat周围. (我正在使用递归,因为我的实时应用程序具有稍微多一点的嵌套结构)我认为,这应该给我所有“theTitle”文本区域,这样我就可以添加消息并随意读取属性。唉,该方法只返回一个“theTitle”组件,日志消息显示了原因:

在生成页面的 DOM 中,id 类似于“myform:myPanelGroup:0:theTitle”(包括 ui:repeat 的迭代计数器),而 bean 只看到 getClientId()s,如 myform:myPanelGroup:theTitle - 并且只存在一次,即最后一次(我猜?)迭代。

最佳答案

您尝试将输入组件绑定(bind)到映射/数组失败,因为 JSF 组件树中没有多个这些组件,而只有一个。 <ui:repeat>在生成 JSF 组件树的 View 构建期间不运行。相反,它在 View 渲染期间运行,生成 HTML 输出。换句话说,<ui:repeat> 的子组件在生成每次迭代的 HTML 输出期间每次都会重复使用。

特定的异常,“Target Unreachable,''BracketSuffix'' returned null” 被抛出是因为变量 #{_lang}在 View 构建期间不可用,即构建 UI 组件树和所有 id 的那一刻和 binding属性被评估。它仅在 View 渲染期间可用。

如果您使用 <c:forEach>,这些绑定(bind)尝试将会成功反而。它在生成 JSF 组件树的 View 构建期间运行。然后,您最终会得到子组件的物理多个实例,这些子组件又会生成自己的 HTML 输出,而不会被多次重用。

由于前面提到的原因,放入一个小组并试图找到所有 child 显然是行不通的。 <ui:repeat>不会在组件树中生成物理上的多个 JSF 组件。相反,它根据当前迭代轮的状态重复使用相同的组件多次生成 HTML 输出。

替换为 <c:forEach>应该工作。也许您遇到了时间问题,因为它在 View 构建期间运行,而您正在准备模型,例如preRenderView而不是 @PostConstruct或者。

如果仔细阅读JSTL in JSF2 Facelets... makes sense?,以上所有内容都更容易理解


至于您的具体功能需求,您通常会使用 Validator为了工作。如果您在输入组件上注册它,那么它会在每一轮迭代中被调用。您将立即拥有具有正确状态的正确输入组件作为 validate() 的第二个参数。方法和提交/转换的值作为第三个参数。

如果您确实需要在之后执行该工作,例如因为您需要了解所有输入,那么您应该以编程方式迭代 <ui:repeat>你自己。你可以在 UIComponent#visitTree() 的帮助下做到这一点这允许您收集每一轮迭代的输入组件的状态。

例如

final FacesContext facesContext = FacesContext.getCurrentInstance();
UIComponent repeat = getItSomehow(); // findComponent, binding, etc.

repeat.visitTree(VisitContext.createVisitContext(facesContext), new VisitCallback() {
@Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (target instanceof UIInput && target.getId().equals("theTitle")) {
String clientId = target.getClientId(facesContext);
Object value = ((UIInput) target).getValue();
// ...
facesContext.addMessage(clientId, message);
}
return VisitResult.ACCEPT;
}
});

另见:

关于jsf-2 - 如何将支持 bean 中的 FacesMessage 附加到 ui :repeat? 中的特定字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19131583/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com