per*_*ssf 131 ajax jsf clientid primefaces jsf-2
下面的代码是从PrimeFaces的DataGrid + DataTable的教程启发和放入<p:tab>一个的<p:tabView>居住在<p:layoutUnit>的<p:layout>.这是代码的内部部分(从p:tab组件开始); 外部是微不足道的.
<p:tabView id="tabs">
<p:tab id="search" title="Search">
<h:form id="insTable">
<p:dataTable id="table" var="lndInstrument" value="#{instrumentBean.instruments}">
<p:column>
<p:commandLink id="select" update="insTable:display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
</p:column>
</p:dataTable>
<p:dialog id="dlg" modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
</h:form>
</p:tab>
</p:tabView>
Run Code Online (Sandbox Code Playgroud)
当我单击时<p:commandLink>,代码停止工作并给出消息:
找不到表达式为"insTable:display"的组件,引用自"tabs:insTable:select".
当我尝试相同的使用时<f:ajax>,它失败了,基本上告诉相同的不同消息:
<f:ajax>包含一个未知的id"insTable:display"无法在组件"tabs:insTable:select"的上下文中找到它
这是怎么造成的,我该如何解决?
Bal*_*usC 293
您需要查看生成的HTML输出以找出正确的客户端ID.在浏览器中打开页面,右键单击并查看源代码.找到感兴趣的JSF组件的HTML表示形式,并将其id作为客户端ID.您可以以绝对方式或相对方式使用它,具体取决于当前的命名容器.见下一章.
注意:如果碰巧包含迭代索引,如:0:,:1:等等(因为它在迭代组件中),那么您需要意识到并不总是支持更新特定的迭代轮次.有关详细信息,请参阅答案底部.
NamingContainer组件并始终为它们提供固定ID如果您要通过ajax process/execute/update/render NamingContainer引用的组件位于同一父级内,则只需引用其自己的ID.
<h:form id="form">
<p:commandLink update="result"> <!-- OK! -->
<h:panelGroup id="result" />
</h:form>
Run Code Online (Sandbox Code Playgroud)
如果它不在同一个内部NamingContainer,那么您需要使用绝对客户端ID来引用它.绝对客户端ID以NamingContainer分隔符开头,默认情况下:.
<h:form id="form">
<p:commandLink update="result"> <!-- FAIL! -->
</h:form>
<h:panelGroup id="result" />
Run Code Online (Sandbox Code Playgroud)
<h:form id="form">
<p:commandLink update=":result"> <!-- OK! -->
</h:form>
<h:panelGroup id="result" />
Run Code Online (Sandbox Code Playgroud)
<h:form id="form">
<p:commandLink update=":result"> <!-- FAIL! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
Run Code Online (Sandbox Code Playgroud)
<h:form id="form">
<p:commandLink update=":otherform:result"> <!-- OK! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
Run Code Online (Sandbox Code Playgroud)
NamingContainer组分是例如<h:form>,<h:dataTable>,<p:tabView>,<cc:implementation>(因此,所有复合材料部件),等等.你通过观察生成的HTML输出容易地识别他们,他们的ID将被预置到所有子组件的所生成的客户端ID.请注意,当它们没有固定ID时,JSF将使用j_idXXX格式化的自动生成ID .你应该通过给他们一个固定的ID来绝对避免这种情况.该OmniFacesNoAutoGeneratedIdViewHandler发展过程中可这很有帮助.
如果您知道找到有UIComponent问题的javadoc ,那么您也可以在那里检查它是否实现了NamingContainer接口.例如,HtmlForm(UIComponent后面的<h:form>标记)显示它实现NamingContainer,但HtmlPanelGroup(UIComponent后面的<h:panelGroup>标记)没有显示它,因此它没有实现NamingContainer.这里是所有标准组件的Javadoc,并在这里是PrimeFaces的javadoc的.
所以在你的情况下:
<p:tabView id="tabs"><!-- This is a NamingContainer -->
<p:tab id="search"><!-- This is NOT a NamingContainer -->
<h:form id="insTable"><!-- This is a NamingContainer -->
<p:dialog id="dlg"><!-- This is NOT a NamingContainer -->
<h:panelGrid id="display">
Run Code Online (Sandbox Code Playgroud)
生成的HTML输出<h:panelGrid id="display">如下所示:
<table id="tabs:insTable:display">
Run Code Online (Sandbox Code Playgroud)
您需要将其id作为客户端ID,然后使用前缀:用于update:
<p:commandLink update=":tabs:insTable:display">
Run Code Online (Sandbox Code Playgroud)
如果此命令链接在include/tagfile中,并且目标位于其外部,因此您不一定知道当前命名容器的命名容器父ID的ID,那么您可以通过UIComponent#getNamingContainer()如下方式动态引用它:
<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">
Run Code Online (Sandbox Code Playgroud)
或者,如果此命令链接位于复合组件内且目标位于其外部:
<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">
Run Code Online (Sandbox Code Playgroud)
或者,如果命令链接和目标都在同一个复合组件内:
<p:commandLink update=":#{cc.clientId}:display">
Run Code Online (Sandbox Code Playgroud)
这一切都被指定为"搜索表达式"中的UIComponent#findComponent()javadoc的:
甲搜索表达式由任一的标识符(其精确匹配对的id属性
UIComponent,或一系列由链接这样的标识符的UINamingContainer#getSeparatorChar字符值.该搜索算法应该如下操作,尽管替代算法的可被使用,只要该最终结果是一样的:
UIComponent通过在满足以下条件之一时立即停止,确定将成为搜索的基础:
- 如果搜索表达式以分隔符开头(称为"绝对"搜索表达式),则基数将是
UIComponent组件树的根.将剥离前导分隔符,并将搜索表达式的其余部分视为"相对"搜索表达式,如下所述.- 否则,如果这
UIComponent是一个NamingContainer它将作为基础.- 否则,搜索此组件的父级.如果
NamingContainer遇到a,它将成为基础.- 否则(如果没有
NamingContainer遇到),rootUIComponent将成为基础.- 搜索表达式(可能在上一步中修改)现在是一个"相对"搜索表达式,用于在基本组件的范围内定位具有匹配id的组件(如果有).比赛按如下方式进行:
- 如果搜索表达式是一个简单的标识符,则将此值与id属性进行比较,然后递归通过基础的facets和子项
UIComponent(除非NamingContainer找到后代,否则不搜索其自己的facet和子项).- 如果搜索表达式包含由分隔符分隔的多个标识符,则第一个标识符用于
NamingContainer通过上一个项目符号点中的规则定位a .然后,将调用findComponent()此方法NamingContainer,传递搜索表达式的其余部分.
请注意,PrimeFaces也遵守JSF规范,但RichFaces使用"一些额外的例外".
"reRender"使用
UIComponent.findComponent()算法(带有一些额外的例外)来查找组件树中的组件.
这些额外的例外情况没有详细描述,但众所周知,相关组件ID(即那些不以其开头的:)不仅在最近的父节点的上下文中搜索NamingContainer,而且NamingContainer在同一视图中的所有其他组件中搜索(这是相对的顺便说一句昂贵的工作).
prependId="false"如果这仍然无效,请验证您是否使用<h:form prependId="false">.在处理ajax提交和呈现期间,这将失败.另请参阅此相关问题:使用prependId ="false"的UIForm中断<f:ajax render>.
它是很长一段时间无法在迭代类似的部件引用特定的迭代项目<ui:repeat>和<h:dataTable>像这样:
<h:form id="form">
<ui:repeat id="list" value="#{['one','two','three']}" var="item">
<h:outputText id="item" value="#{item}" /><br/>
</ui:repeat>
<h:commandButton value="Update second item">
<f:ajax render=":form:list:1:item" />
</h:commandButton>
</h:form>
Run Code Online (Sandbox Code Playgroud)
但是,由于Mojarra 2.2.5 <f:ajax>开始支持它(它只是停止验证它;因此你再也不会面对提到异常的问题;后来计划另一个增强修复).
这仅适用于当前的MyFaces 2.2.7和PrimeFaces 5.2版本.未来版本可能会提供支持.同时,最好的办法是更新迭代组件本身,或者更新父组件,以防它不呈现HTML,例如<ui:repeat>.
PrimeFaces Search Expressions允许您通过JSF组件树搜索表达式引用组件.JSF有几个内置:
@this:当前组件@form:父母 UIForm@all:整个文件@none: 没有PrimeFaces通过新的关键字和复合表达式支持增强了这一功能:
@parent:父组件@namingcontainer:父母 UINamingContainer@widgetVar(name):由给定的组件识别的组件 widgetVar您还可以在复合表达式,如混合这些关键字@form:@parent,@this:@parent:@parent等等.
PrimeFaces选择器(PFS)在@(.someclass)允许你通过jQuery CSS选择语法基准分量.例如,引用HTML输出中具有所有通用样式类的组件.如果您需要引用"很多"组件,这将特别有用.这仅预先确定目标组件在HTML输出中具有所有客户端ID(固定或自动生成,无关紧要).另请参见更新="@(.myClass)"中的PrimeFaces选择器如何工作?
首先:据我所知,在tabview中放置对话框是一种不好的做法......你最好把它拿出来......
现在问你的问题:
对不起,花了我一些时间来确定你想要实现什么,
我刚刚在我的网络应用程序上做了,它的确有效
正如我之前说的那样将p:对话框放在`p:tabView旁边,
按照您最初的建议离开p:对话框:
<p:dialog modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
Run Code Online (Sandbox Code Playgroud)
并且p:commandlink应该看起来像这样(我所做的就是更改update属性)
<p:commandLink update="display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
Run Code Online (Sandbox Code Playgroud)
同样适用于我的网络应用程序,如果它不适合你,那么我猜你的java bean代码有问题...
小智 5
这是因为选项卡是一个命名容器以及...你的更新应该是update="Search:insTable:display"你可以做什么,只是将你的对话框放在表单之外,仍然在选项卡内,然后它将是:update="Search:display"
| 归档时间: |
|
| 查看次数: |
150802 次 |
| 最近记录: |