带有 prependId="false" 的 UIForm 中断 <f:ajax render>

Posted

技术标签:

【中文标题】带有 prependId="false" 的 UIForm 中断 <f:ajax render>【英文标题】:UIForm with prependId="false" breaks <f:ajax render> 【发布时间】:2011-11-16 22:21:21 【问题描述】:

我对事实背后的想法有疑问,即只有 UIForm 获得了属性 prependId。为什么NamingContainer接口中没有指定属性?您现在可能会说这是因为向后兼容性,但我更愿意打破兼容性并让实现该接口的用户也实现 prependId 事物的方法。

从我的角度来看,UIForm 组件中 prependId 的主要问题是,它会破坏 findComponent() 我希望如果我使用prependId,那么NamingContainer 的行为会发生变化,这不仅与渲染有关,而且在想要在组件树中搜索组件时也会发生变化。

这里是一个简单的例子:

<h:form id="test" prependId="false">
  <h:panelGroup id="group"/>
</h:form>

现在,当我想获取 panelGroup 组件时,我希望将字符串 "group" 传递给方法 findComponent(),但它找不到任何东西,我必须改用 "test:group"

具体的问题是,当使用带有prependId="false" 的ajax 时。 ajax 标记期望在属性更新和处理中,值关心命名容器。有点奇怪,当我使用prependId="false" 时,我必须指定完整的 id 或路径,但没关系。

<h:form id="test" prependId="false">
  <h:panelGroup id="group"/>
</h:form>
<h:form id="test1" prependId="false">
  <h:commandButton value="go">
    <f:ajax render="test:group"/>
  </h:commandButton>
</h:form>

好吧,这段代码将毫无问题地呈现,但它不会更新 panelGroup,因为它找不到它。 PartialViewContext 将仅包含 id "group" 作为 renderIds 的元素。我不知道这是否是预期的,可能是这样,但我不知道代码。现在我们到了findComponent() 方法找不到组件的地步,因为作为参数传递的表达式是"group",而该方法期望"test:group" 找到组件。

一种解决方案是编写自己的findComponent(),这是我选择处理此问题的方式。在这个方法中,我处理一个组件,它是一个NamingContainer,并且像普通的UIComponent 一样将属性 prependId 设置为 false。对于每个提供 prependId 属性的UIComponent,我都必须这样做,这很糟糕。反射将有助于绕过类型的静态定义,但它仍然不是一个真正干净的解决方案。

另一种方法是在NamingContainer 接口中引入 prependId 属性,并将findComponent() 的行为更改为如上所述。

最后提出的解决方案是更改 ajax 标记的行为以传递整个 id,但这只会解决 ajax 问题,而不是 findComponent() 实现背后的编程问题。

您对此有何看法?为什么要这样实施?我不可能是第一个遇到这个问题的人,但是我找不到相关的主题?!

【问题讨论】:

一个确实知道如何揭示事物的程序员编写的精美案例。谢谢克里斯蒂安。 【参考方案1】:

确实,&lt;f:ajax render&gt; 所做的 UIComponent#findComponent() 在使用 &lt;h:form prependId="false"&gt; 时会失败。这个问题是已知的并且是“无法修复”:JSF spec issue 573。

以我的拙见,在 JSF 1.2 时代,他们不应该将 prependId 属性添加到 UIForm。这样做只是为了让 j_security_check 用户满意,他们希望使用带有 JSF 输入组件的 JSF 表单(j_security_check 需要精确的输入字段名称 j_usernamej_password 不能通过配置修改) .但他们并没有完全意识到在 JSF 1.2 期间引入了另一项改进,它使您能够继续使用 &lt;form&gt; 而不是坚持使用 &lt;h:form&gt;。然后 CSS/jQuery 纯粹主义者开始滥用 prependId="false" 以避免在他们选择不当的 CSS 选择器中转义分隔符 :

永远不要使用prependId="false"

对于j_security_check,只需使用&lt;form&gt; 或新的Servlet 3.0 HttpServletRequest#login()。另见Performing user authentication in Java EE / JSF using j_security_check。

对于 CSS 选择器,如果您绝对需要 ID 选择器(因此不需要更可重用的类选择器),只需将感兴趣的组件包装在纯 html &lt;div&gt;&lt;span&gt; 中。

另见:

How to select JSF components using jQuery? How to use JSF generated HTML element ID with colon ":" in CSS selectors? By default, JSF generates unusable ids, which are incompatible with css part of web standards

【讨论】:

好吧,我遇到了 findComponent() 算法的另一个“问题”,或者它是什么不同的东西。当我尝试在其外部更新数据表的特定行时,找不到组件 ID。我使用这样的东西: 为什么ajax标签不能解析组件?我检查了来源,但不知道为什么它不起作用。我应该将父 NamingContainer 作为查找的基础,然后找到 dataTable,迭代到行并最终找到 subElement,但它没有! Ajax标签有点奇怪……

以上是关于带有 prependId="false" 的 UIForm 中断 <f:ajax render>的主要内容,如果未能解决你的问题,请参考以下文章

总是运行带有 failOnError="false" 的 Liquibase changeSet?

带有 FriendlyUrls 和 debug="false" 的 ASP.NET WebForms 项目在生产中引发 404

带有 Rails UJS 的 jQuery Mobile 在使用 data-method="delete" 的链接上尊重 data-ajax="false"

MongoDB:请求一个带有“select:false”的字段以及所有标准字段

如何使用多个 JSF 表单

带有多个信息窗口的Google地图