jsf - How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar" -
the following code inspired primefaces datagrid + datatable tutorials , put <p:tab>
of <p:tabview>
residing in <p:layoutunit>
of <p:layout>
. here inner part of code (starting p:tab
component); outer part 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 click <p:commandlink>
, code stops working , gives message:
cannot find component expression "instable:display" referenced "tabs:instable:select".
when try same using <f:ajax>
, fails different message telling same:
<f:ajax>
contains unknown id "instable:display" cannot locate in context of component "tabs:instable:select"
how caused , how can solve it?
look in html output actual client id
you need in generated html output find out right client id. open page in browser, rightclick , view source. locate html representation of jsf component of interest , take id
client id. can use in absolute or relative way depending on current naming container. see following chapter.
note: if happens contain iteration index :0:
, :1:
, etc (because it's inside iterating component), need realize updating specific iteration round not supported. see bottom of answer more detail on that.
memorize namingcontainer
components , give them fixed id
if component you'd reference ajax process/execute/update/render inside same namingcontainer
parent, reference own id.
<h:form id="form"> <p:commandlink update="result"> <!-- ok! --> <h:panelgroup id="result" /> </h:form>
if it's not inside same namingcontainer
, need reference using absolute client id. absolute client id starts namingcontainer
separator character, 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 example <h:form>
, <h:datatable>
, <p:tabview>
, <cc:implementation>
(thus, composite components), etc. recognize them looking @ generated html output, id prepended generated client id of child components. note when don't have fixed id, jsf use autogenerated id in j_idxxx
format. should absolutely avoid giving them fixed id. omnifaces noautogeneratedidviewhandler
may helpful in during development.
if know find javadoc of uicomponent
in question, can check in there whether implements namingcontainer
interface or not. example, htmlform
(the uicomponent
behind <h:form>
tag) shows implements namingcontainer
, htmlpanelgroup
(the uicomponent
behind <h:panelgroup>
tag) not show it, not implement namingcontainer
. here javadoc of standard components , here javadoc of primefaces.
solving problem
so in case of:
<p:tabview id="tabs"><!-- namingcontainer --> <p:tab id="search"><!-- not namingcontainer --> <h:form id="instable"><!-- namingcontainer --> <p:dialog id="dlg"><!-- not namingcontainer --> <h:panelgrid id="display">
the generated html output of <h:panelgrid id="display">
looks this:
<table id="tabs:instable:display">
you need take id
client id , prefix :
usage in update
:
<p:commandlink update=":tabs:instable:display">
referencing outside include/tagfile/composite
if command link inside include/tagfile, , target outside it, , don't know id of naming container parent of current naming container, can dynamically reference via uicomponent#getnamingcontainer()
so:
<p:commandlink update=":#{component.namingcontainer.parent.namingcontainer.clientid}:display">
or, if command link inside composite component , target outside it:
<p:commandlink update=":#{cc.parent.namingcontainer.clientid}:display">
or, if both command link , target inside same composite component:
<p:commandlink update=":#{cc.clientid}:display">
see get id of parent naming container in template in render / update attribute
how work under covers
this specified "search expression" in the uicomponent#findcomponent()
javadoc:
a search expression consists of either identifier (which matched against id property of
uicomponent
, or series of such identifiers linkeduinamingcontainer#getseparatorchar
character value. search algorithm should operates follows, though alternate alogrithms may used long end result same:
- identify
uicomponent
base searching, stopping 1 of following conditions met:
- if search expression begins the separator character (called "absolute" search expression), base root
uicomponent
of component tree. leading separator character stripped off, , remainder of search expression treated "relative" search expression described below.- otherwise, if
uicomponent
namingcontainer
serve basis.- otherwise, search parents of component. if
namingcontainer
encountered, base.- otherwise (if no
namingcontainer
encountered) rootuicomponent
base.- the search expression (possibly modified in previous step) "relative" search expression used locate component (if any) has id matches, within scope of base component. match performed follows:
- if search expression simple identifier, value compared id property, , recursively through facets , children of base
uicomponent
(except if descendantnamingcontainer
found, own facets , children not searched).- if search expression includes more 1 identifier separated separator character, first identifier used locate
namingcontainer
rules in previous bullet point. then,findcomponent()
method ofnamingcontainer
called, passing remainder of search expression.
note primefaces adheres jsf spec, richfaces uses "some additional exceptions".
"rerender" uses
uicomponent.findcomponent()
algorithm (with additional exceptions) find component in component tree.
those additional exceptions in detail described, it's known relative component ids (i.e. not starting :
) not searched in context of closest parent namingcontainer
, in other namingcontainer
components in same view (which relatively expensive job way).
never use prependid="false"
if still doesn't work, verify if aren't using <h:form prependid="false">
. fail during processing ajax submit , render. see related question: uiform prependid="false" breaks <f:ajax render>.
referencing specific iteration round of iterating components
it long time not possible reference specific iterated item in iterating components <ui:repeat>
, <h:datatable>
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 <f:ajax>
started support (it stopped validating it; never face in question mentioned exception anymore; enhancement fix planned later).
this doesn't work yet in current myfaces 2.2.7 , primefaces 5.2 versions. support might come in future versions. in meanwhile, best bet update iterating component itself, or parent in case doesn't render html, <ui:repeat>
.
when using primefaces, consider search expressions or selectors
primefaces search expressions allows reference components via jsf component tree search expressions. jsf has several builtin:
@this
: current component@form
: parentuiform
@all
: entire document@none
: nothing
primefaces has enhanced new keywords , composite expression support:
@parent
: parent component@namingcontainer
: parentuinamingcontainer
@widgetvar(name)
: component identified givenwidgetvar
you can mix keywords in composite expressions such @form:@parent
, @this:@parent:@parent
, etc.
primefaces selectors (pfs) in @(.someclass)
allows reference components via jquery css selector syntax. e.g. referencing components having common style class in html output. particularly helpful in case need reference "a lot of" components. prerequires target components have client id in html output (fixed or autogenerated, doesn't matter). see how primefaces selectors in update="@(.myclass)" work?
Comments
Post a Comment