JSF rendering ajax outside of form [duplicate] - ajax
The following code is inspired from PrimeFaces DataGrid + DataTable Tutorials and put into a <p:tab> of a <p:tabView> residing in a <p:layoutUnit> of a <p:layout>. Here is the inner part of the code (starting from p:tab component); the outer part is trivial.
<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>
When I click the <p:commandLink>, the code stops working and gives the message:
Cannot find component with expression "insTable:display" referenced from "tabs:insTable:select".
When I try the same using <f:ajax>, then it fails with a different message basically telling the same:
<f:ajax> contains an unknown id "insTable:display" cannot locate it in the context of the component "tabs:insTable:select"
When it happens during another Ajax postback and the JSF project stage is set to Development, then it fails with a JavaScript alert with the message:
malformedXML: During update: insTable:display not found
How is this caused and how can I solve it?
Look in HTML output for actual client ID
You need to look in the generated HTML output to find out the right client ID. Open the page in browser, do a rightclick and View Source. Locate the HTML representation of the JSF component of interest and take its id as client ID. You can use it in an absolute or relative way depending on the current naming container. See following chapter.
Note: if it happens to contain iteration index like :0:, :1:, etc (because it's inside an iterating component), then you need to realize that updating a specific iteration round is not always supported. See bottom of answer for more detail on that.
Memorize NamingContainer components and always give them a fixed ID
If a component which you'd like to reference by ajax process/execute/update/render is inside the same NamingContainer parent, then just reference its own ID.
<h:form id="form">
<p:commandLink update="result"> <!-- OK! -->
<h:panelGroup id="result" />
</h:form>
If it's not inside the same NamingContainer, then you need to reference it using an absolute client ID. An absolute client ID starts with the NamingContainer separator character, which is by default :.
<h:form id="form">
<p:commandLink update="result"> <!-- FAIL! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- OK! -->
</h:form>
<h:panelGroup id="result" />
<h:form id="form">
<p:commandLink update=":result"> <!-- FAIL! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
<h:form id="form">
<p:commandLink update=":otherform:result"> <!-- OK! -->
</h:form>
<h:form id="otherform">
<h:panelGroup id="result" />
</h:form>
NamingContainer components are for example <h:form>, <h:dataTable>, <p:tabView>, <cc:implementation> (thus, all composite components), etc. You recognize them easily by looking at the generated HTML output, their ID will be prepended to the generated client ID of all child components. Note that when they don't have a fixed ID, then JSF will use an autogenerated ID in j_idXXX format. You should absolutely avoid that by giving them a fixed ID. The OmniFaces NoAutoGeneratedIdViewHandler may be helpful in this during development.
If you know to find the javadoc of the UIComponent in question, then you can also just check in there whether it implements the NamingContainer interface or not. For example, the HtmlForm (the UIComponent behind <h:form> tag) shows it implements NamingContainer, but the HtmlPanelGroup (the UIComponent behind <h:panelGroup> tag) does not show it, so it does not implement NamingContainer. Here is the javadoc of all standard components and here is the javadoc of PrimeFaces.
Solving your problem
So in your case of:
<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">
The generated HTML output of <h:panelGrid id="display"> looks like this:
<table id="tabs:insTable:display">
You need to take exactly that id as client ID and then prefix with : for usage in update:
<p:commandLink update=":tabs:insTable:display">
Referencing outside include/tagfile/composite
If this command link is inside an include/tagfile, and the target is outside it, and thus you don't necessarily know the ID of the naming container parent of the current naming container, then you can dynamically reference it via UIComponent#getNamingContainer() like so:
<p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display">
Or, if this command link is inside a composite component and the target is outside it:
<p:commandLink update=":#{cc.parent.namingContainer.clientId}:display">
Or, if both the command link and target are inside same composite component:
<p:commandLink update=":#{cc.clientId}:display">
See also Get id of parent naming container in template for in render / update attribute
How does it work under the covers
This all is specified as "search expression" in the UIComponent#findComponent() javadoc:
A search expression consists of either an identifier (which is matched exactly against the id property of a UIComponent, or a series of such identifiers linked by the UINamingContainer#getSeparatorChar character value. The search algorithm should operates as follows, though alternate alogrithms may be used as long as the end result is the same:
Identify the UIComponent that will be the base for searching, by stopping as soon as one of the following conditions is met:
If the search expression begins with the the separator character (called an "absolute" search expression), the base will be the root UIComponent of the component tree. The leading separator character will be stripped off, and the remainder of the search expression will be treated as a "relative" search expression as described below.
Otherwise, if this UIComponent is a NamingContainer it will serve as the basis.
Otherwise, search up the parents of this component. If a NamingContainer is encountered, it will be the base.
Otherwise (if no NamingContainer is encountered) the root UIComponent will be the base.
The search expression (possibly modified in the previous step) is now a "relative" search expression that will be used to locate the component (if any) that has an id that matches, within the scope of the base component. The match is performed as follows:
If the search expression is a simple identifier, this value is compared to the id property, and then recursively through the facets and children of the base UIComponent (except that if a descendant NamingContainer is found, its own facets and children are not searched).
If the search expression includes more than one identifier separated by the separator character, the first identifier is used to locate a NamingContainer by the rules in the previous bullet point. Then, the findComponent() method of this NamingContainer will be called, passing the remainder of the search expression.
Note that PrimeFaces also adheres the JSF spec, but RichFaces uses "some additional exceptions".
"reRender" uses UIComponent.findComponent() algorithm (with some additional exceptions) to find the component in the component tree.
Those additional exceptions are nowhere in detail described, but it's known that relative component IDs (i.e. those not starting with :) are not only searched in the context of the closest parent NamingContainer, but also in all other NamingContainer components in the same view (which is a relatively expensive job by the way).
Never use prependId="false"
If this all still doesn't work, then verify if you aren't using <h:form prependId="false">. This will fail during processing the ajax submit and render. See also this related question: UIForm with prependId="false" breaks <f:ajax render>.
Referencing specific iteration round of iterating components
It was for long time not possible to reference a specific iterated item in iterating components like <ui:repeat> and <h:dataTable> like so:
<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>
However, since Mojarra 2.2.5 the <f:ajax> started to support it (it simply stopped validating it; thus you would never face the in the question mentioned exception anymore; another enhancement fix is planned for that later).
This only doesn't work yet in current MyFaces 2.2.7 and PrimeFaces 5.2 versions. The support might come in the future versions. In the meanwhile, your best bet is to update the iterating component itself, or a parent in case it doesn't render HTML, like <ui:repeat>.
When using PrimeFaces, consider Search Expressions or Selectors
PrimeFaces Search Expressions allows you to reference components via JSF component tree search expressions. JSF has several builtin:
#this: current component
#form: parent UIForm
#all: entire document
#none: nothing
PrimeFaces has enhanced this with new keywords and composite expression support:
#parent: parent component
#namingcontainer: parent UINamingContainer
#widgetVar(name): component as identified by given widgetVar
You can also mix those keywords in composite expressions such as #form:#parent, #this:#parent:#parent, etc.
PrimeFaces Selectors (PFS) as in #(.someclass) allows you to reference components via jQuery CSS selector syntax. E.g. referencing components having all a common style class in the HTML output. This is particularly helpful in case you need to reference "a lot of" components. This only prerequires that the target components have all a client ID in the HTML output (fixed or autogenerated, doesn't matter). See also How do PrimeFaces Selectors as in update="#(.myClass)" work?
first of all: as far as i know placing dialog inside a tabview is a bad practice... you better take it out...
and now to your question:
sorry, took me some time to get what exactly you wanted to implement,
did at my web app myself just now, and it works
as I sayed before place the p:dialog out side the `p:tabView ,
leave the p:dialog as you initially suggested :
<p:dialog modal="true" widgetVar="dlg">
<h:panelGrid id="display">
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
and the p:commandlink should look like this (all i did is to change the update attribute)
<p:commandLink update="display" oncomplete="dlg.show()">
<f:setPropertyActionListener value="#{lndInstrument}"
target="#{instrumentBean.selectedInstrument}" />
<h:outputText value="#{lndInstrument.name}" />
</p:commandLink>
the same works in my web app, and if it does not work for you , then i guess there is something wrong in your java bean code...
It's because the tab is a naming container aswell... your update should be update="Search:insTable:display" What you can do aswell is just place your dialog outside the form and still inside the tab then it would be: update="Search:display"
Please note that from PrimeFaces 10 and up, you are able to use observer and event.
This allows you to update components based on a custom event name, set by the #obs(event) keyword. For example:
<p:commandButton update="#obs(myEvent)"/>
<h:panelGroup>
<p:autoUpdate on="myEvent"/>
</h:panelGroup>
See:
https://www.primefaces.org/showcase/ui/ajax/observer.xhtml
I know this already has a great answer by BalusC but here is a little trick I use to get the container to tell me the correct clientId.
Remove the update on your component that is not working
Put a temporary component with a bogus update within the component you were trying to update
hit the page, the servlet exception error will tell you the correct client Id you need to reference.
Remove bogus component and put correct clientId in the original update
Here is code example as my words may not describe it best.
<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"
Remove the failing update within this component
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">
Add a component within the component of the id you are trying to update using an update that will fail
<p:commandButton id="BogusButton" update="BogusUpdate"></p:commandButton>
<h:outputText value="Name:" />
<h:outputText value="#{instrumentBean.selectedInstrument.name}" />
</h:panelGrid>
</p:dialog>
</h:form>
</p:tab>
</p:tabView>
Hit this page and view the error.
The error is:
javax.servlet.ServletException: Cannot find component for expression "BogusUpdate" referenced from
tabs:insTable: BogusButton
So the correct clientId to use would then be the bold plus the id of the target container (display in this case)
tabs:insTable:display
Try change update="insTable:display" to update="display". I believe you cannot prefix the id with the form ID like that.
Related
How to dynamically show/hide components under p:tab via ajax?
Forgive me I am not even sure my question is correctly stated. I am trying to unravel relationship between p:tab and h:panelGroup. I have very shallow understanding of JSF. I have following code. <p:tabView id="view"> <p:tab id="A"> ... <p:ajax event="change" update="C,D" listener="#{bean.captureValue}"/> </p:tab> <p:tab id="B" titleStyleClass="x"> <h:panelGroup id="C"> <h:panelGroup rendered="#{bean.checkValue eq 'Yes'}"/> <f:facet name="title"><table>...</table></f:facet> <div>....</div> </h:panelGroup> </h:panelGroup> <h:panelGroup id="D"> <h:panelGroup rendered="#{bean.checkValue eq 'No'}"/> <f:facet name="title"><table>.....</table></f:facet> <div>....</div> </h:panelGroup> </h:panelGroup> </p:tab> </p:tabView> So within component id="A", a user selects a value from drop down menu, bean captures it and dynamically show or hide component id="C" or "D" based on the value. First time try, I didn't have any h:panelGroup tags. I used rendered attribute directly from p:tab component however I realized that unless I refresh the entire page, the bean.checkValue wouldn't know latest value captured. By reading many articles in this forum, I realized I have to wrap it with h:panelGroup which in turn worked by showing either h:panelGroup "C" or "D" based on the value selected from p:tab tag with id="A". However the contents of f:facet tag is not visible anymore. It has html table tag which contains h:outputText with static value and p:graphicImage. I am not sure why and hope someone can solve this mystery. Update: Thanks to Arthur. I was able to fix the issue with his help. I paste here code that performs expected output. <p:tabView id="view"> <p:tab id="A"> ... <p:ajax event="change" update="view" listener="#{bean.captureValue}"/> </p:tab> <p:tab id="B" titleStyleClass="x"> <f:facet name="title"> <ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/> <table>...</table> </ui:fragment> </f:facet> <ui:fragment rendered="#{bean.checkValue eq 'Yes'}"/> <div>...</div> </ui:fragment> <f:facet name="title"> <ui:fragment rendered="#{bean.checkValue eq 'No'}"/> <table>...</table> </ui:fragment> </f:facet> <ui:fragment rendered="#{bean.checkValue eq 'No'}"/> <div>...</div> </ui:fragment> </p:tab> </p:tabView>
Facets are representing a named section within a container component. Container for your facets are in both cases <h:panelGroup> and this component doesn't define any facet which you could use. As you don't provide in your sample code any name for the facet (which is mandatory) I only assume that maybe you would like to use a title facet for a tab, as <p:tab> component define facet named "title". Then it should look like <p:tab id="B"> <f:facet name="title" > <h:outputText value="Test1" rendered="#{bean.checkValue}"/> <h:outputText value="Test2" rendered="#{!bean.checkValue}"/> </f:facet> </p:tab> , so you implement rendering logic inside facet value (you decide which title would be displayed. This logic could be also moved to backing bean. Keep in mind that in primefaces sometimes components doesn't handle very well and you could try then use them as an attribute instead of facets as stands in this post It is also possible that you misunderstand meaning of facets. The best way to explain them are the facets defined i component. Authors of this component wanted to provide for users possibility to define header and footer of datatable. Then you, as a jsf user can compose header for instance, from other different components. You could also check this post where facets are also explained. One more thing to add is that using <h:panelGroup rendered="#{bean.checkValue}"/> for render logic is considred as bad pattern as it is going to produce a <span> element in your code. Instead you should use <ui:fragment rendered="#{bean.checkValue}"/> which is intended for rendering logic and it won't produce any additional html code
partial page rendering (PPR) with faces-redirect
I'm using PrimeFaces 3.5 and I faced a problem with partial page rendering. I need to load content from a Facelet file into "dynamic" part of a template. index.xhtml: <f:view> <h:form id="form1"> <p:outputPanel layout="block"> <p:commandButton action="content-2?faces-redirect=false" update="display" /> </p:outputPanel> <p:outputPanel id="display" layout="block"> content 1 </p:outputPanel> </h:form> </f:view> content-2.xhtml: <h:body> content 2 loaded </h:body> When I click on the <p:commandButton>, then content-2.xhtml will be opened. However, this refreshes the whole page. The XML response contains like this: <partial-response><changes><update id="javax.faces.ViewRoot"> When I change the action attribute to a method expression: <f:view> <h:form id="form1"> <p:outputPanel layout="block"> <p:commandButton action="#{myBean.increment}" update="display" /> </p:outputPanel> <p:outputPanel id="display" layout="block"> #{myBean.count} </p:outputPanel> </h:form> </f:view> Then the display block updates as expected. The XML response contains like this: <partial-response><changes><update id="form:display"> Why does the action="content-2?faces-redirect=false" way update the entire page? I also tried to <ui:composition>, but in this case this reloads "static" part of template. I do not want it.
This is fully normal and expected behavior if you navigate to a different view by supplying a non-null outcome in the action attribute. JSF will then overrule the partial render with a render of #all. JSF/Facelets won't somehow automagically retain the common components in the tree as you seemed to expect. If you intend to dynamically change the component tree during a partial page rendering, then you need inside the <p:outputPanel id="display" layout="block"> either a dynamic include something like this (section is just an integer) <ui:include src="section#{bean.section}.xhtml" /> or multiple conditionally rendered sections <ui:fragment rendered="#{bean.section == 1}"><ui:include src="section1.xhtml" /></ui:fragment> <ui:fragment rendered="#{bean.section == 2}"><ui:include src="section2.xhtml" /></ui:fragment> <ui:fragment rendered="#{bean.section == 3}"><ui:include src="section3.xhtml" /></ui:fragment> <ui:fragment rendered="#{bean.section == 4}"><ui:include src="section4.xhtml" /></ui:fragment> Each has its own pros and cons depending on whether the include file contains form/input/command components and/or references view scoped beans. The <ui:include> runs namely during view build time like JSTL. See for more detail also JSTL in JSF2 Facelets... makes sense? The presence of faces-redirect=false is not significant as it's the default already. If it were true, then a JavaScript window.location would be invoked on the target URL.
Display a list of images in a table format in JSF
This is probably a really simple JSF question, but I can't seem to find the simple answer. I have a List of images, and I want to display them in a table of images. Each image is displayed with its filename. I'm using a ui:repeat tag as shown below. I don't get 5 columns as requested, however, only 1. <h:panelGrid id="resourcePanel" columns="5" rules="all"> <ui:repeat var="res" value="#{resourceUpload.resources}"> <h:panelGrid columns="1" rules="none"> <h:graphicImage value="/image/resource?id=#{res.idAsString}" style="width:100px;" /> <h:outputText value="#{res.name}" /> </h:panelGrid> </ui:repeat> </h:panelGrid>
The output is fully as expected and specified. The <ui:repeat> is a render time tag, not a view build time tag like <c:forEach>. After building the view, <h:panelGrid> ends up with 1 child component (the <ui:repeat> itself), not with n nested <h:panelGrid> components like as you would get with <c:forEach>. <html ... xmlns:c="http://java.sun.com/jsp/jstl/core"> ... <h:panelGrid id="resourcePanel" columns="5" rules="all"> <c:forEach var="res" items="#{resourceUpload.resources}"> <h:panelGrid columns="1" rules="none"> <h:graphicImage value="/image/resource?id=#{res.idAsString}" style="width:100px;" /> <h:outputText value="#{res.name}" /> </h:panelGrid> </c:forEach> </h:panelGrid> (this has in the Mojarra versions older than 2.1.18 however an implication on #{resourceUpload}: it can't be a view scoped bean, it must be request scoped due to a chicken-egg issue in view state saving/restoring; you'd need to upgrade to Mojarra 2.1.18) Your nested <h:panelGrid> makes by the way no utter sense. I'd have used <h:panelGroup> here. See also: JSTL in JSF2 Facelets... makes sense? - to understand "view build time" vs "view render time" better create table columns dynamically in JSF - another similar question
Why do you use another <h:panelGrid> inside the <ui:repeat>? You can just use a div like this. Instead of <h:panelGrid columns="1" rules="none"> use <div style="display:inline-block;"> Edit: I don't think that you can do it with <ui:repeat>. Use <c:forEach> instead. First you should import the namespace xmlns:c="http://java.sun.com/jstl/core" Now replace the <ui:repeat> with <c:forEach> like this. <c:forEach items="#{accountMastList.resultList}" var="res">
Value to update attribute of primefaces command button
I have a query here regarding the value given to the update attribute of the primefaces command button. Here is a simple code. I have a simple xhtml page <h:body> <h:form id="main"> <p:growl id="maingrowl" showDetail="true"></p:growl> <p:panelGrid id="mainpanel" columns="2"> <p:commandButton value="Ajax Submit" update="test" id="ajax" actionListener="#{mytestBean.display}" /> </p:panelGrid> <p:panelGrid id="test" rendered="#{mytestBean.show}" columns="1"> <h:inputText value="#{mytestBean.val1}" /> <h:inputText value="#{mytestBean.val2}" /> <p:commandButton value="value in" id="aj" update="test" actionListener="#{mytestBean.displaysec}"> </p:commandButton> </p:panelGrid> </h:form> </h:body> Now, If I have to update the panelgrid "test" then in the first command button I have to provide the id "test" prefixed with ":main:" in the update attribute of the command button since that is the exact id in the HTML DOM as I find it in the view source in the browser. But, I was able to update even by given just "test" in the update attribute. So my question here is when should I use the ":" in the id or is it mandatory or is there any pre defined rule to give the id's in the attribute? Also, I am aware of the fact that the id given in the update attribute is through the UINamingContainer in which it is placed. Please pardon me if its trivial, I am really confused here. Any help greatly appreciated. Thank you.
If both components (the one to update and the one that triggers the update) are inside the same NamingContainer, the relative client id withoud the : is sufficient. NamingContainers in jsf are all those components that prepend their own id to the client id of all child components, e.g. <h:form>, <h:dataTable> or <ui:repeat> (or to be more precise: all components that implement the javax.faces.component.NamingContainer interface). If both components are not inside the same NamingContainer, you have to use the absolute id beginning with a : from the view root. If you are interested in more detailed information I recommend reading the javadoc of the UIComponent#findComponent() method where the search algorithm is described. Note that the : is the default character to separate segments of a clientId. You can change it with a context parameter in your web.xml.
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
The following code is inspired from PrimeFaces DataGrid + DataTable Tutorials and put into a <p:tab> of a <p:tabView> residing in a <p:layoutUnit> of a <p:layout>. Here is the inner part of the code (starting from p:tab component); the outer part is trivial. <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> When I click the <p:commandLink>, the code stops working and gives the message: Cannot find component with expression "insTable:display" referenced from "tabs:insTable:select". When I try the same using <f:ajax>, then it fails with a different message basically telling the same: <f:ajax> contains an unknown id "insTable:display" cannot locate it in the context of the component "tabs:insTable:select" When it happens during another Ajax postback and the JSF project stage is set to Development, then it fails with a JavaScript alert with the message: malformedXML: During update: insTable:display not found How is this caused and how can I solve it?
Look in HTML output for actual client ID You need to look in the generated HTML output to find out the right client ID. Open the page in browser, do a rightclick and View Source. Locate the HTML representation of the JSF component of interest and take its id as client ID. You can use it in an absolute or relative way depending on the current naming container. See following chapter. Note: if it happens to contain iteration index like :0:, :1:, etc (because it's inside an iterating component), then you need to realize that updating a specific iteration round is not always supported. See bottom of answer for more detail on that. Memorize NamingContainer components and always give them a fixed ID If a component which you'd like to reference by ajax process/execute/update/render is inside the same NamingContainer parent, then just reference its own ID. <h:form id="form"> <p:commandLink update="result"> <!-- OK! --> <h:panelGroup id="result" /> </h:form> If it's not inside the same NamingContainer, then you need to reference it using an absolute client ID. An absolute client ID starts with the NamingContainer separator character, which is by default :. <h:form id="form"> <p:commandLink update="result"> <!-- FAIL! --> </h:form> <h:panelGroup id="result" /> <h:form id="form"> <p:commandLink update=":result"> <!-- OK! --> </h:form> <h:panelGroup id="result" /> <h:form id="form"> <p:commandLink update=":result"> <!-- FAIL! --> </h:form> <h:form id="otherform"> <h:panelGroup id="result" /> </h:form> <h:form id="form"> <p:commandLink update=":otherform:result"> <!-- OK! --> </h:form> <h:form id="otherform"> <h:panelGroup id="result" /> </h:form> NamingContainer components are for example <h:form>, <h:dataTable>, <p:tabView>, <cc:implementation> (thus, all composite components), etc. You recognize them easily by looking at the generated HTML output, their ID will be prepended to the generated client ID of all child components. Note that when they don't have a fixed ID, then JSF will use an autogenerated ID in j_idXXX format. You should absolutely avoid that by giving them a fixed ID. The OmniFaces NoAutoGeneratedIdViewHandler may be helpful in this during development. If you know to find the javadoc of the UIComponent in question, then you can also just check in there whether it implements the NamingContainer interface or not. For example, the HtmlForm (the UIComponent behind <h:form> tag) shows it implements NamingContainer, but the HtmlPanelGroup (the UIComponent behind <h:panelGroup> tag) does not show it, so it does not implement NamingContainer. Here is the javadoc of all standard components and here is the javadoc of PrimeFaces. Solving your problem So in your case of: <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"> The generated HTML output of <h:panelGrid id="display"> looks like this: <table id="tabs:insTable:display"> You need to take exactly that id as client ID and then prefix with : for usage in update: <p:commandLink update=":tabs:insTable:display"> Referencing outside include/tagfile/composite If this command link is inside an include/tagfile, and the target is outside it, and thus you don't necessarily know the ID of the naming container parent of the current naming container, then you can dynamically reference it via UIComponent#getNamingContainer() like so: <p:commandLink update=":#{component.namingContainer.parent.namingContainer.clientId}:display"> Or, if this command link is inside a composite component and the target is outside it: <p:commandLink update=":#{cc.parent.namingContainer.clientId}:display"> Or, if both the command link and target are inside same composite component: <p:commandLink update=":#{cc.clientId}:display"> See also Get id of parent naming container in template for in render / update attribute How does it work under the covers This all is specified as "search expression" in the UIComponent#findComponent() javadoc: A search expression consists of either an identifier (which is matched exactly against the id property of a UIComponent, or a series of such identifiers linked by the UINamingContainer#getSeparatorChar character value. The search algorithm should operates as follows, though alternate alogrithms may be used as long as the end result is the same: Identify the UIComponent that will be the base for searching, by stopping as soon as one of the following conditions is met: If the search expression begins with the the separator character (called an "absolute" search expression), the base will be the root UIComponent of the component tree. The leading separator character will be stripped off, and the remainder of the search expression will be treated as a "relative" search expression as described below. Otherwise, if this UIComponent is a NamingContainer it will serve as the basis. Otherwise, search up the parents of this component. If a NamingContainer is encountered, it will be the base. Otherwise (if no NamingContainer is encountered) the root UIComponent will be the base. The search expression (possibly modified in the previous step) is now a "relative" search expression that will be used to locate the component (if any) that has an id that matches, within the scope of the base component. The match is performed as follows: If the search expression is a simple identifier, this value is compared to the id property, and then recursively through the facets and children of the base UIComponent (except that if a descendant NamingContainer is found, its own facets and children are not searched). If the search expression includes more than one identifier separated by the separator character, the first identifier is used to locate a NamingContainer by the rules in the previous bullet point. Then, the findComponent() method of this NamingContainer will be called, passing the remainder of the search expression. Note that PrimeFaces also adheres the JSF spec, but RichFaces uses "some additional exceptions". "reRender" uses UIComponent.findComponent() algorithm (with some additional exceptions) to find the component in the component tree. Those additional exceptions are nowhere in detail described, but it's known that relative component IDs (i.e. those not starting with :) are not only searched in the context of the closest parent NamingContainer, but also in all other NamingContainer components in the same view (which is a relatively expensive job by the way). Never use prependId="false" If this all still doesn't work, then verify if you aren't using <h:form prependId="false">. This will fail during processing the ajax submit and render. See also this related question: UIForm with prependId="false" breaks <f:ajax render>. Referencing specific iteration round of iterating components It was for long time not possible to reference a specific iterated item in iterating components like <ui:repeat> and <h:dataTable> like so: <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> However, since Mojarra 2.2.5 the <f:ajax> started to support it (it simply stopped validating it; thus you would never face the in the question mentioned exception anymore; another enhancement fix is planned for that later). This only doesn't work yet in current MyFaces 2.2.7 and PrimeFaces 5.2 versions. The support might come in the future versions. In the meanwhile, your best bet is to update the iterating component itself, or a parent in case it doesn't render HTML, like <ui:repeat>. When using PrimeFaces, consider Search Expressions or Selectors PrimeFaces Search Expressions allows you to reference components via JSF component tree search expressions. JSF has several builtin: #this: current component #form: parent UIForm #all: entire document #none: nothing PrimeFaces has enhanced this with new keywords and composite expression support: #parent: parent component #namingcontainer: parent UINamingContainer #widgetVar(name): component as identified by given widgetVar You can also mix those keywords in composite expressions such as #form:#parent, #this:#parent:#parent, etc. PrimeFaces Selectors (PFS) as in #(.someclass) allows you to reference components via jQuery CSS selector syntax. E.g. referencing components having all a common style class in the HTML output. This is particularly helpful in case you need to reference "a lot of" components. This only prerequires that the target components have all a client ID in the HTML output (fixed or autogenerated, doesn't matter). See also How do PrimeFaces Selectors as in update="#(.myClass)" work?
first of all: as far as i know placing dialog inside a tabview is a bad practice... you better take it out... and now to your question: sorry, took me some time to get what exactly you wanted to implement, did at my web app myself just now, and it works as I sayed before place the p:dialog out side the `p:tabView , leave the p:dialog as you initially suggested : <p:dialog modal="true" widgetVar="dlg"> <h:panelGrid id="display"> <h:outputText value="Name:" /> <h:outputText value="#{instrumentBean.selectedInstrument.name}" /> </h:panelGrid> </p:dialog> and the p:commandlink should look like this (all i did is to change the update attribute) <p:commandLink update="display" oncomplete="dlg.show()"> <f:setPropertyActionListener value="#{lndInstrument}" target="#{instrumentBean.selectedInstrument}" /> <h:outputText value="#{lndInstrument.name}" /> </p:commandLink> the same works in my web app, and if it does not work for you , then i guess there is something wrong in your java bean code...
It's because the tab is a naming container aswell... your update should be update="Search:insTable:display" What you can do aswell is just place your dialog outside the form and still inside the tab then it would be: update="Search:display"
Please note that from PrimeFaces 10 and up, you are able to use observer and event. This allows you to update components based on a custom event name, set by the #obs(event) keyword. For example: <p:commandButton update="#obs(myEvent)"/> <h:panelGroup> <p:autoUpdate on="myEvent"/> </h:panelGroup> See: https://www.primefaces.org/showcase/ui/ajax/observer.xhtml
I know this already has a great answer by BalusC but here is a little trick I use to get the container to tell me the correct clientId. Remove the update on your component that is not working Put a temporary component with a bogus update within the component you were trying to update hit the page, the servlet exception error will tell you the correct client Id you need to reference. Remove bogus component and put correct clientId in the original update Here is code example as my words may not describe it best. <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" Remove the failing update within this component 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"> Add a component within the component of the id you are trying to update using an update that will fail <p:commandButton id="BogusButton" update="BogusUpdate"></p:commandButton> <h:outputText value="Name:" /> <h:outputText value="#{instrumentBean.selectedInstrument.name}" /> </h:panelGrid> </p:dialog> </h:form> </p:tab> </p:tabView> Hit this page and view the error. The error is: javax.servlet.ServletException: Cannot find component for expression "BogusUpdate" referenced from tabs:insTable: BogusButton So the correct clientId to use would then be the bold plus the id of the target container (display in this case) tabs:insTable:display
Try change update="insTable:display" to update="display". I believe you cannot prefix the id with the form ID like that.