Jsf 2 如何将支持bean中的FacesMessage附加到ui中的特定字段:repeat?
我有一个输入元素数量可变的表单,如下所示:Jsf 2 如何将支持bean中的FacesMessage附加到ui中的特定字段:repeat?,jsf-2,facelets,messages,uirepeat,backing-beans,Jsf 2,Facelets,Messages,Uirepeat,Backing Beans,我有一个输入元素数量可变的表单,如下所示: <ui:repeat var="_lang" value="#{myBean.languages}"> <h:inputTextarea value="${_lang.title}" id="theTitle" /> <h:messages for="theTitle"/> </ui:repeat> 我在节点上调用它,它是ui:repeat周围h:panelGroup的绑定ui组件。(我
<ui:repeat var="_lang" value="#{myBean.languages}">
<h:inputTextarea value="${_lang.title}" id="theTitle" />
<h:messages for="theTitle"/>
</ui:repeat>
我在节点上调用它,它是ui:repeat
周围h:panelGroup
的绑定ui组件。(我使用递归是因为我的实时应用程序有一个稍微嵌套的结构)我认为这应该给我所有的“标题”文本区域,这样我就可以随意添加消息和读取属性。唉,该方法只返回一个“theTitle”组件,日志消息显示了原因:
在生成页面的DOM中,ID类似于“myform:myPanelGroup:0:theTitle”(包括ui:repeat
的迭代计数器),而bean只看到getClientId()s,如myform:myPanelGroup:theTitle
,并且只存在一次,最后一次(我想是吧?)迭代。尝试将输入组件绑定到映射/数组失败,因为JSF组件树中没有多个组件,只有一个。
在生成JSF组件树的视图构建期间不会运行。相反,它在视图呈现时运行,生成HTML输出。换句话说,
的子组件在每次迭代生成HTML输出时都会被重用
抛出特定的异常“Target Unreachable”,“BracketSuffix”“returned null”,因为变量{u lang}
在视图构建期间不可用,此时构建UI组件树并计算所有id
和绑定
属性。它仅在视图渲染期间可用
如果改用
,这些绑定尝试就会成功。它在视图构建期间运行,生成JSF组件树。然后,您将得到子组件的多个物理实例,这些实例依次生成各自的HTML输出,而无需重复使用多次
由于前面提到的原因,加入一个小组并试图找到所有的孩子显然是行不通的。
不会在组件树中实际生成多个JSF组件。相反,它重用同一组件多次生成HTML输出,具体取决于当前迭代轮的状态
用
替换应该有效。可能您正面临时间问题,因为它在视图构建期间运行,并且您正在准备模型,例如,preRenderView
,而不是@PostConstruct
等等
如果你仔细阅读,以上所有内容都更容易理解
至于您的具体功能需求,您通常会使用验证器
进行工作。如果您在输入组件上注册它,那么它将在每一轮迭代中被调用。您将立即获得具有正确状态的正确输入组件作为validate()
方法的第二个参数,并将提交/转换的值作为第三个参数
如果您确实需要在之后执行作业,例如,因为您需要了解所有输入,那么您应该自己以编程方式迭代
。您可以借助它来实现这一点,它允许您收集每个迭代轮的输入组件状态
例如
另见:
还有另一种选择:自己更换整个面部信息。用21点。而且
无论如何,基于与我们的讨论,我们选择了避免整个visitTree混乱,并建立我们自己的消息机制。这包括:
1) 包含多重映射映射的ViewScope bean:
private Map<Object, Multimap<String, String>> fieldValidationMessages = new HashMap<>();
private Map fieldValidationMessages=new HashMap();
这将对象
作为字段标识符(可以是相应的bean本身、UI组件,甚至是运行时在UI:repeat
中生成的字符串
。然后,该标识符可以在另一个任意数量的子字段上具有任意数量的字符串
消息。非常灵活
bean还提供了方便的方法来获取和设置字段和子字段上的消息,以及检查是否存储了任何消息(即是否存在验证错误)
2) 一个简单的xhtml include,用于显示给定字段的错误消息,并替换“h:messages for…”
就这样。关键在于,它在生命周期的应用程序和呈现阶段而不是JSF自己的验证阶段运行。但是,由于我们的项目已经决定进行bean验证而不是生命周期验证,这不是一个问题。我觉得第一个或最后一个方法最接近。最后一个只能是一些奇怪的JSTL版本的东西。类似这样的东西工作得很好,只是在集合上迭代就不行了。第一个。。。要是那个奇怪的括号错误没有发生就好了……我在七年前找到了一个有问题的人,但他们也没有解决。谢谢你的扩展答案,这是一条新的、有价值的信息!非常非常有趣!因此visitTree()可以看到getChildren()不存在的东西。好。。。只要它起作用——而且确实如此。:)有一个奇怪的例外:当我从两个元素的列表生成网页时,DOM包含myform:0和myform:1,但visitTree声称也在访问myform:2,它看起来只是myform:1的克隆。这是出于设计吗?换句话说,我现在只得到三个“theTitle”(客户端id无效),而不是(使用我先前的getChildren()尝试)得到一个“theTitle”,最后一个迭代计数不存在。正确的数字应该是两个“标题”…不,模型仍然只包含两行。但我会在试验台上检查。。。明天在实际的项目代码中发生了太多的事情。哪个JSF impl/version?如果是莫哈拉,那就做吧
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;
}
});
private Map<Object, Multimap<String, String>> fieldValidationMessages = new HashMap<>();