How to update a composite component form from another composite component? - jsf

I'm having problem trying to update an external form. To be more clear, I have a primary form that includes 2 different composite components, lets call include1 and include2. The page I want to update is the include2 being update after a search from a include1.
this is how the 2 pages are being included.
<ui:define name="include1">
<ui:param name="mbean" value="#{currentBean}" />
<libcomp:include1 />
</ui:define>
<ui:define name="include2">
<ui:param name="mbean" value="#{currentBean}" />
<libcomp:include2>
</ui:define>
Now, in include1 I have a button that tries to update the form inside include2
update="include2Form"
and in the include2 I have
<cc:implementation>
<h:form
id="include2Form">
When I try to load the page I always get an Error 500 saying that the "include2Form" has not been found!
I tried some research before coming here but none helped me, I tried to change the form to a div, tried to pass id by parameter, a panel, form with prependId=false etc...
Using fireBug I found out that JSF or Primefaces is adding an random String to my form/components ID...as
id="j_idt99:include2Form:myTable"
I think that is the reason of my problem and I'm trying to find a work around.
Could anyone help me please???

First of all, the additional string in your ID directly comes frome JSF, unrelated to PrimeFaces, because the Composite Component itself is a UINamingContainer. This is expected behavoir and even necessary, because otherwise you would end up in duplicate ID conflicts, when using the same CC multiple times in the same view.
In my opinion it is bad design to have a form inside a Composite Component at all. To improve reusability just get rid of that form and work with process, partialSubmit, maybe f:subView etc..
Beside that you should rethink your design. The point that one Composite Component has to update s.th. outside the component might be an indicator, that a Composite Component is not the perfect approach to cover your requirements.
However, if you really have to update some parts of your view outside the composite component, just pass the ID of what to update via a composite attribute to your CC and let the CC not care about what and where to update
<composite:interface>
<composite:attribute name="update" required="true" />
</composite:interface>

Related

primefaces update attribute not working on modal dialog opened from modal dialog [duplicate]

I have a question about the idea behind the fact, that only UIForm got the attribute prependId. Why is the attribute not specified in the NamingContainer interface? You will now probably say that's because of backward compability but I would preferre breaking the compability and let users which implement that interface, also implement methods for the prependId thing.
The main problem from my perspective about the prependId in the UIForm component is, that it will break findComponent()
I would expect that if I use prependId, then the NamingContainer behaviour would change, not only related to rendering but also when wanting to search for components in the component tree.
Here a simple example:
<h:form id="test" prependId="false">
<h:panelGroup id="group"/>
</h:form>
Now when i want to get the panelGroup component I would expect to pass the string "group" to the method findComponent(), but it won't find anything, I have to use "test:group" instead.
The concrete problem with that is, when using ajax with prependId="false". The ajax tag expects in the attributes update and process, that the values care of naming containers. It's a bit strange that when I use prependId="false" that I have to specify the full id or path, but okay.
<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>
Well this code will render without problems but it won't update the panelGroup because it cannot find it. The PartialViewContext will contain only the id "group" as element of the renderIds. I don't know if this is expected, probably it is but I don't know the code. Now we come to the point where the method findComponent() can not find the component because the expression passed as parameter is "group" where the method would expect "test:group" to find the component.
One solution is to write your own findComponent() which is the way I chose to deal with this problem. In this method i handle a component which is a NamingContainer and has the property prependId set to false like a normal UIComponent. I will have to do that for every UIComponent which offers a prependId attribute and that is bad. Reflection will help to get around the static definition of types but it's still not a really clean solution.
The other way would be introducing the prependId attribute in the NamingContainer interface and change the behaviour of findComponent() to work like described above.
The last proposed solution would be changing the behaviour of the ajax tag to pass the whole id, but this would only solve the ajax issue and not the programmatic issues behind the findComponent() implementation.
What do you think about that and why the hell is it implemented like that? I can't be the first having this problem, but I wasn't able to find related topics?!
Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.
In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.
Just don't use prependId="false", ever.
For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.
For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.
See also:
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

Accessing JSF nested composite component elements in JavaScript

I am trying to DRY up popup windows in my JSF 2 project using composite components.
This code base uses Icefaces 3.3.0 (with their 1.8.2 compatibility layer for historical reasons), Mojarra 2.2.7, and Glassfish 4.1.
I have input.xhtml which provides a text input and uses a 2-button popup (ok/cancel), which in turn builds on the basic popup.
input.xhtml:
<composite:interface>
<!-- ... -->
<composite:editableValueHolder name="forInput" targets="theInput"/>
</composite:interface>
<composite:implementation>
<my:popup2Buttons>
<ice:inputText id="theInput" value="..."/>
<script>setInputFocus("#{cc.clientId}:theInput");</script>
</my:popup2Buttons>
</composite:implementation>
popup2buttons.xhtml:
<composite:interface>
<!-- ... -->
</composite:interface>
<composite:implementation>
<my:popup>
<composite:insertChildren/>
<ice:commandButton id="OkButton"
value="Ok"
actionListener="..."/>
<ice:commandButton id="CancelButton"
value="Cancel"
actionListener="..."/>
</my:popup>
</composite:implementation>
popup.xhtml:
<composite:interface>
<!-- ... -->
</composite:interface>
<composite:implementation>
<script>
function setInputFocus(id) {
document.getElementById(id).focus();
}
</script>
<ice:panelPopup>
<f:facet name="body">
<h:panelGroup>
<composite:insertChildren/>
</h:panelGroup>
</f:facet>
</ice:panelPopup>
</composite:implementation>
The popup works mostly as expected, i.e., I can enter something, the ok and cancel buttons work, and validation works as well.
What does not work is my JavaScript code that tries to focus the input when the popup opens.
When I look at the page in Firebug, I see that the input's ID is MyForm:j_idt63:j_idt64:j_idt67:theInput, but the JavaScript code tries to focus an element with the ID MyForm:j_idt63:theInput.
Why is #{cc.clientId} in input.xhtml not the correct ID that the input ends up getting later? What do I need to do to make this work?
I've seen BalusC's hint on adding a binding but I don't want a binding so that the composite component can be independent of any backing beans.
Is there something else I am missing here?
Composite components are implicitly naming containers. I.e. they prepend their ID to the client ID of the children. This makes it possible to use multiple of them in the same view without their children causing duplicate IDs in generated HTML output.
In your specific case, you wrapped the input field in another composite which is in turn wrapped in again another composite. If you're absolutely positive that you don't need multiple naming containers wrapping in each other in this specific composition, then those (popup2buttons.xhtml and popup.xhtml) probably shouldn't be composites, but rather <ui:decorate> templates or <ui:composition> tagfiles. See also When to use <ui:include>, tag files, composite components and/or custom components?
Coming back to the technical problem, it's caused because the #{cc.clientId} does not refer the ID of the nested composite component, but of the current composite component. And thus this would be off. As to the potential solution with binding, the answer which you found does nowhere tell that you should use a backing bean for this. The binding="#{foo}" code in the answer was as-is. It really works that way, without a bean property, see also JSF component binding without bean property. However, this construct would indeed fail when you include the same composite multiple times in the same view and thus multiple components share the same binding="#{foo}". It indeed isn't supposed to be shared by multiple components, see also What is component binding in JSF? When it is preferred to be used?
To solve this without a backing bean, you can use a so-called backing component.
com.example.InputComposite
#FacesComponent("inputComposite")
public class InputComposite extends UINamingContainer {
private UIInput input;
// +getter+setter.
}
input.xhtml
<cc:interface componentType="inputComposite">
...
</cc:interface>
<cc:implementation>
...
<h:inputText binding="#{cc.input}" ... />
<script>setInputFocus("#{cc.input.clientId}");</script>
...
</cc:implementation>
The alternative is to rework them into templates or tagfiles. Be careful that you don't overvalue/overuse composites.

Composite component in ui:repeat vs c:forEach using ajax calls

I have a composite component, which represents an item that will be stored in a list. I would like to display these items using <ui:repeat>, but I have problems making ajax calls. The thing is that for <f:ajax> render attribute, I want to give the id of my component through
#{cc.clientId}
However this raises error when I use it with <ui:repeat>, because of the reasons that are explained in this document https://rogerkeays.com/jsf-c-foreach-vs-ui-repeat.
<cc:implementation>
<div id="#{cc.clientId}">
<h:form>
<h:commandLink styleClass="btn btn-info" value="Click me">
<f:ajax execute="#form"
render=":#{cc.clientId}"/>
</h:commandLink>
</h:form>
</div>
</cc:implementation>
Is there a way to make the above component work using <ui:repeat> (for example is there a component which can replace the <f:ajax> tag handler, or are we stuck to <c:forEach> construct)?
<ui:repeat id="myComponent" value="#{backingBean.myComponentItem}" var="item" varStatus="itemIndex">
<components:exampleComponent id="myComponent"/>
</ui:repeat>
So I start using <c:forEach> instead of <ui:repeat>, and I was able to use the id of my component in the render attribute of <f:ajax>. But this time when I make pagination, if the size of the list decreases I start having empty components in my page. For solving this I started doing pagination through ajax calls and this solved the empty component problem.
Just I thought everything was solved I encountered another problem: lets say I have a page listing 10 components, and I went to another page, and from that page I came to the component displaying page again, but for some reason lets say this time I retrieved only 3 items from database, and I just want to display these 3 items through my components but nothing else.. Unfortunately in this scenario, 3 items are displayed correctly, but the page also contains 7 empty components too. For overcoming this I need to redirect to this page one-more time. So I just gave up at this point. Apart from this I also eventually get the exception below, when the number of the components on the page changes.
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.sun.faces.application.view.StateHolderSaver
I tried using the suggestion explained in the post Jsf Error : java.lang.ClassCastException, but it didn't work for me, I started getting another error which is similar to above exception.
<context-param>
<param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
<param-value>/pagename.xhtml</param-value>
</context-param>
So after these long explanations I would just like to learn what is the best approach for creating composite components which are ajax-enabled, who are fully responsible of their own-states and independent of other components, and that can be displayed in the page more than once and the number of components may vary during the page life-cycle (through pagination, navigation etc).
So far the best solution I came up with is, to check number of components in the page and when that number changes through an ajax call or because of a navigation from another page, redirect to the destination page one more time, this refreshes the empty components in the page without creating much disturbance to users. If you come up with any better solution please let us know.

JSF composite:insertFacet and composite:renderFacet

I want to have a composite component with a facet in it, which I implement in my "implementation" of this composite component. My problem are ids, because when I only define in my composite component and then with put my implementation in it, it only renders it but the component is in another place.
Here is a sample code:
myComposition.xhtml
<composite:implementation>
<composite:renderFacet name="myFacet">
</composite:implementation>
myCompositionImpl.xhtml
<mySomething:myComposition>
<f:facet name="myFacet">
this code is rendered but the "component" which I define here is not placed
logically in the place where I defined the "renderFacet".
</f:facet>
</mySomething:myComposition>
What can I do about this? With composite:insertFacet it doesn't render anything. I need to have the component also there because I need to know the client id of it.
Just to clarify:
Did you specify <cc:facet name="myFacet"> within the interface of the component?
Furthermore what exactly do you mean with in another place?
Some tips:
renderFacet is correct, insertFacet is for facets defined within the composite itself.
Try adding "<!-- -->" as the first line of content of your facet, this suppose to be a workaround for a bug regarding single line facet content.
I got it working. The problem was I had to figure out the clientId of the facet inserted and I didn't know that each composite-component makes it own NamingContainer.
I had something like that:
"myComposition2.xhtml"
...
"index.faces"
and the resulting clientId was: myC2:myC1:

Why prependId="false" in a jsf form?

I know what prependId="false" does. It set the flag so that the id of the form does not prepend the id of the form child, but why? any particular reason why you do or dont want to prepend id?
In my experience, I never use this attribute. However, in some cases it can be useful.
When you use Facelets, you can create templates or include pages inside another page. So you can imagine that a page could be included in several different pages. Take the example where the parent pages contain a form, with different id:
Page 1:
<h:form id="form1">
<ui:include src="pages/my-page.xhtml"/>
...
</h:form>
Page 2:
<h:form id="form2">
<ui:include src="pages/my-page.xhtml"/>
...
</h:form>
Now, in the my-page.xhtml, you have a <h:inputText id="foo"/>. In the first case, the real ID of the input will be form1:foo, while in the second case, it will be form2:foo. This could create complex situations if you need a direct access to this component in Javascript or in Java (using findComponent("...") method).
If you use prependId="false" (or on some components forceId="true"), the real ID will be simply foo, and then your code will be simpler as you will not have to care about the container of the input field.
However, you will have to use this attribute carefully, as you may get a duplicate ID error if you use this prepend attribute too often...
In modern jsf versions it might also break ajax, see UIForm with prependId="false" breaks <f:ajax render>
A situation where prependId=false is useful is in the login form, if you are using Spring Security, because the ids of the inputtexts have to be exactly "j_username" and "j_password". So you shouldn't put the form id before them, and using prependId=false is a good choice to acheive this.
I prefer to add prependId occasionally to make styling elements via their ID classes easier. For example, a form:
<h:form id="myform" ... >
<h:inputText id="mytext" ... />
</h:form>
Would give you an ID of myform:mytext. As the colon is reserved in CSS, you have to escape the CSS to read something like #myform\:mytext { ... } which I prefer not to do. With prependId="false" I get to use just #mytext { ... } which is much simpler & nicer to read. It also plays nicer with CSS preprocessors like LESS or Sass.
One scenario where we have to set this flag is in case of Autocomplete control of primefaces library.
I had to set this flag to false when I was trying AutoComplete control of primefaces library. I was not able to get autocomplete working but after setting this flag it worked fine. You can see this link to my question regarding this problem
WARN [Parameters] Parameters: Invalid chunk ignored. warning coming in primefaces application
In addition to making for CSS selectors easier, using prependId=false makes it easier to use JavaScript and jQuery to access specific elements.
Otherwise, without using RichFaces, to get at an elmement by id using jQuery you'll have to use an ugly escape sequence like:
jQuery("form-id\\:element-id")

Resources