Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
661 views
in Technique[技术] by (71.8m points)

jsf 2 - Rerendering composite component by ajax

I have build a composite component witch looks something like this:

<composite:interface>
  <composite:attribute name="id" required="false" />
  <composite:attribute name="label" required="true" />
</composite:interface>

<composite:implementation>
  <h:panelGroup id="#{cc.attrs.id}">
    <fieldset class="fieldset"><legend>${cc.attrs.label}</legend></fieldset>
  </h:panelGroup>  
</composite:implementation>

The compent displays the current label correctly.

<xyz:comp id="idMyComponent" label="#{someBean.text}"/>

...
<a4j:ajax ... render="idMyComponent" />
...

Now when the action is preformed nothing happens. However when I add a Postfix to the ID in the component it works fine (see below).

...
<composite:implementation>
      <h:panelGroup id="#{cc.attrs.id}Label">
...

And define the ID in render with the postfix:

<xyz:comp id="idMyComponent" label="#{someBean.text}"/>

...
<a4j:ajax ... render="idMyComponentLabel" />
...

Can some on explain to me why it only works when I add a postfix to the ID in h:panelGroup?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This problem is actually two-fold.

The first problem is that the <xyz:comp id> actually specifies the ID of the composite component itself, the <cc:implementation>. This is by default nowhere represented in HTML output and therefore ajax/JavaScript can't locate it by document.getElementById() and friends.

Actually, your <h:panelGroup id="#{cc.attrs.id}"> ends up in generated HTML output as follows (rightclick page and View Source to see it yourself):

<span id="idMyComponent:idMyComponent">

The second "problem" is that RichFaces/Ajax4jsf has enhanced the referencing/finding of JSF components in the tree by relative client ID (i.e. not starting with :) by not only searching in the context of the current NamingContainer, but also in all other NamingContainer components. A composite component is inherently also a NamingContainer component.

Your first attempt failed because it found the composite itself instead of the panel group, but JS/ajax in turn failed to update because there doesn't exist any HTML element with id="myComponent" in the generated HTML output.

Your second attempt succeeded because it finally found the real panel group (note: because it also searched in all other NamingContainer components; this would still have failed if you've used <f:ajax> instead of <a4j:ajax>).

The right way to fix your problem is not using #{cc.attrs.id} on a JSF component, but using #{cc.clientId} on a plain HTML element.

<span id="#{cc.clientId}">

(yes, use a <span> or <div> instead of <h:panelGroup> inside the <cc:implementation>)

This way JSF can find the component by client ID (in order to generate the proper ajax response) and JS can find the HTML element by client ID (in order to update the right HTML element based on ajax response).

See also:


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...