JSF: how avoid 'Component ID has already been found in the view.' error on double insert of composite component - jsf

I know what causes the following problem. I am looking for an elegant way to address the problem rather than a brute-force (and non-DRY) workaround I've found.
I have a highly reusable h:form in a template (and I am aware of the dangers of "god forms", this is not quite a god form), and I insert editable content into that form via the template, with an identical action bar of command buttons both at the top and the bottom of the page. (There hundreds of clients to this template, and some insert different actions bars into the template.)
The only reason I am doing this (bar top and bottom) is user convenience; I have found when using many content management systems that it is annoying to have to scroll down or scroll up to find a Save button (or other buttons in an action bar) on long forms.
The template (please don't tell me it's a "god form") has:
<h:form prependId=".." id="form">
<div id="actions-upper" class="actions">
<ui:insert name="actions"/>
</div>
... other reusable stuff
<div id="actions-lower" class="actions">
<ui:insert name="actions"/>
</div>
</h:form>
Every edit.xhtml page (there are lots of them) that is a client to a template inserts the action bar, along with a compatible #{manager} backing bean parameter:
<ui:composition template="/template.xhtml">
...
<ui:define name="actions">
<util:edit_actions id="edit_actions" manager="#{manager}"/>
</ui:define>
... other insertions with editable content omitted
Note how above I have given that CC `util:edit_actions' an id (which I did not do on this CC until recently for reasons I'll explain below).
So you can see that the exact same actions toolbar is inserted into the top and bottom just inside form section of a page. If, however, you do this as shown above with an id passed for edit_actions you get:
javax.servlet.ServletException: Component ID edit_actions has already been found in the view.
I have been using this template with success for years until I introduced the explicit id, for reasons now illustrated below.
The edit_actions CC has some command buttons such as:
<composite:implementation>
<p:toolbar>
<p:toolbarGroup>
<p:commandButton
ajax ="true"
action="#{cc.attrs.manager.crud.update}"
value="Save"
update="#form"
id="save"
/>
...
Now that general Save button is not always the only button in the form; there are sometimes other buttons that perform interim AJAX actions with conditionally required input fields, such as this from an embedded links table editor:
<p:inputText
id="newLinkUrl"
value="#{cc.attrs.manager.newLinkUrl}"
required="#{param['edit_actions:save']==null}"
validator="urlValidator"
/>
<p:commandButton
value="Add new link !"
action="#{cc.attrs.manager.addNewLink(cc.attrs.element)}"
update="... newLinkUrl ..."
/>
(Where BTW that urlValidator does NOT throw on null, the system relies on the conditional required for that so that the general #form Save always works.)
But to get the conditional required to work:
required="#{param['edit_actions:save']==null}"
I have to give the inserted edit_actions CC an explicit id whenever performing the insert in any of the hundreds of edit.xhtml client pages that use it:
<ui:composition template="/template.xhtml">
...
<ui:define name="actions">
<util:edit_actions id="edit_actions" manager="#{manager}"/>
</ui:define>
But as shown above, if I do include the id there, it now causes an error (but without it I can't use the conditional required trick).
There are two workarounds I've found so far:
Simply don't have the action bar in the template twice. This is unacceptable, it simply breaks the feature by avoiding it.
Having 2 different insertion points in the template does work, but you have to be careful with the IDs.
And are problems with the 2nd one:
<ui:composition template="/template.xhtml">
<ui:define name="actions_upper">
<util:edit_actions id="edit_actions_upper" manager="#{manager}"/>
</ui:define>
<ui:define name="actions_lower">
<util:edit_actions id="edit_actions_lower" manager="#{manager}"/>
</ui:define>
Note that this code above is not Don't Repeat Yourself (DRY) code, which I consider one of the most important coding practices, and something JSF is usually particularly good at addressing. Ensuring that the above template insertion pattern and id pattern is addressed in hundreds of edit.xhtml page is just plain error prone, unless I can somehow encapsulate that ui:define pair while still being able to inject any compatible #{manager}.
And the conditional required test then has to test on both upper and lower Save buttons:
<p:inputText
id="newLinkUrl"
value="#{cc.attrs.manager.newLinkUrl}"
required="#{param['edit_actions_upper:save']==null and param['edit_actions_lower:save']==null}"
validator="urlValidator"
/>
All in all, a rather ugly non-DRY workaround.
Q1: Is there any way I can somehow dynamically change the id of an inserted edit_action.xhtml automatically so that it can appear in the template in 2 different places without a clashing component id error ?
Q2: Alternatively, is there some way I can encapsulate the two ui:define in the workaround for the upper vs lower bar insertion (as show in workaround 2.), while still having the ability to inject the #{manager} (so that I can include it and reuse it as encapsulated policy in hundreds of edit.xhtml clients to the template) ?
EDIT: this attempt to encapsulate my "double action bar" pattern does not seem to work. From /include/edit_actions_defines.xhtml:
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:util="http://xmlns.jcp.org/jsf/composite/util">
<ui:define name="actions_upper">
<util:edit_actions id="edit_actions_upper" manager="#{manager}"/>
</ui:define>
<ui:define name="actions_lower">
<util:edit_actions id="edit_actions_lower" manager="#{manager}"/>
</ui:define>
</ui:composition>
With attempted use by edit.xhtml:
<ui:composition template="/template.xhtml">
<ui:include src="/include/edit_actions_defines.xhtml">
<ui:param name="manager" value="#{specificManager}"/>
</ui:include>
Seems to be ignored silently.

I've found an solution (workaround really) to my own problem meeting my requirements. Not pretty, but might be of use to others.
Instead of testing for a specific component id, I use a regexp:
/**
* Searches for a component id ending in ":save".
*
* #return
*/
public boolean isSaveButtonPressed() {
Map<String, String> parameterMap = FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap();
for (String key : parameterMap.keySet()) {
boolean matches = Pattern.matches("^j.*:save",key);
if (matches) return true;
}
return false;
}
And the required test is simply:
<p:inputText
id="newLinkUrl"
value="#{cc.attrs.manager.newLinkUrl}"
required="#{not cc.attrs.manager.saveButtonPressed}"
validator="urlValidator"
/>
Then when inserting my util:edit_actions component (which is to appear both top and bottom of the form via the template for user convenience) I don't pass it an explicit id, I just let JSF generate them, and they are different (no longer clash) for both Save buttons.
So I can have my twice-injected edit_actions cake and eat it. The required test on the URL string field fails correctly as desired for both Save buttons.

Related

Why are validations from my JSF composite facet being done when the facet is not rendered

I have a problem that validations from a composite's facet are being fired even when I do not render the composite.
I stripped the problem down to the following barebones code.
Here is the composite entityDetailPanel:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:p="http://primefaces.org/ui"
xmlns:common="http://java.sun.com/jsf/composite/common">
<composite:interface>
<composite:attribute name="prefix" required="true" />
<composite:facet name="lowerPanel"/>
</composite:interface>
<composite:implementation>
<h:form id="#{cc.attrs.prefix}entityDetailForm2"
styleClass="#{cc.attrs.prefix}EntityDetailPanelForm #{cc.attrs.prefix}Listener" >
<p:messages id="#{cc.attrs.prefix}messages" autoUpdate="true" closable="true"/>
<p:commandButton
value="SAVE"
update="#(.#{cc.attrs.prefix}Listener), #(.#{cc.attrs.prefix}EntityDetailPanelForm}"/>
<composite:renderFacet name="lowerPanel" rendered="false"/>
</h:form>
</composite:implementation>
</ui:composition>
And here is the invocation:
<?xml version="1.0" encoding="UTF-8"?>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:common="http://xmlns.jcp.org/jsf/composite/common">
<common:entityDetailPanel id="foo" prefix="Instruments">
<f:facet name="lowerPanel">
<!-- <p:inputText id="assetClassPrompt" required="true" requiredMessage="Why do we get this message?"/>-->
<p:selectOneMenu id="assetClassPrompt" required="true" requiredMessage="Why do we get this message?"
value="#{instrumentController.selectedData.assetClass}">
<f:selectItem itemLabel="foo" itemValue="foo"/>
<f:selectItem itemLabel="bar" itemValue="bar"/>
</p:selectOneMenu>
</f:facet>
</common:entityDetailPanel>
</ui:composition>
The combobox does NOT show on the screen (because it's not rendered), but why would I be getting a validation for something that's not rendered?
This is what I see when I click the SAVE button:
Stranger yet, is that I see THIS validation error even on other invocations of the composite that do NOT have that combobox.
I also noticed that if I do not include a unique ID on the <messages> tag, the message from one use of the composite will show up in other uses of the composite.
Is this a PrimeFaces or JSF bug, or am I missing something?
You might notice that I have a commented out <inputText> tag. It's worth mentioning that when I replace the <selectOneMenu> and replace it with the <inputText> I no longer see the problem.
I thought it might help to elucidate a bit on the larger problem I'm trying to solve.
I want to create something akin to a <p:layout> that has both fixed elements (for all uses of the composite) and non-fixed elements/panels which are passed in parametrically (for EACH use of the component).
Here is a screenshot where the items indicated in read are things that vary with each invocation of the composite. Everything else is always present in all invocations of the composite.
As you can see, the parameters are:
A button panel (buttons vary depending on context)
Some additional fields to add to the end of a form (which might contain validations
An entire lower panel (which might contain validations)
It's worth mentioning that all these things are validated together (for "SAVE" buttons), so it's desirable to have the <form> tag be within the composite output (which includes the panels passed in as parameters).
This problem is two-fold.
First, the <cc:renderFacet> is never designed to work this way. It does not support the rendered attribute. That it somehow works is because the facet is internally re-interpreted as an UIPanel component and all attributes are (incorrectly) automatically inherited from the tag. You should not rely on that. The rendered attribute is incorrectly considered during render response, causing confusing behavior that it "works". This is technically a bug in the JSF implementation. The attributes are (correctly) not inherited during the postback, causing the trouble you observed. The components are still decoded and validated "in spite of" that they are not rendered.
Second, the <p:inputText> extends from UIInput which checks before validation if there's any submitted value. A submitted value of null is interpreted as complete absence of the input field in the form, so it's skipped. A submitted value of an empty string is interpeted as an empty value, so it's validated. The <p:selectOneMenu>, however, has overriden the standard UIInput behavior and considers null the same way as an empty string. Even when the submitted value is null (which means that the input field wasn't in the form at all), it's still being validated. This is technically a bug in PrimeFaces side.
Your intent is at least clear: conditionally render a facet. The <cc:xxx> tags are evaluated during Facelets compile time (which is a step before view build time), so conditionally building the <cc:renderFacet> using JSTL <c:if> will also not ever work.
Your best bet is redefining "render lower panel" as a composite attribute, and create a backing component to explicitly copy this attribute into the facet after it's being added to the view.
<cc:interface componentType="entityDetailPanelComposite">
...
<cc:facet name="lowerPanel" />
<cc:attribute name="renderLowerPanel" type="java.lang.Boolean" default="false" />
</cc:interface>
<cc:implementation>
<f:event type="postAddToView" listener="#{cc.init}" />
...
<cc:renderFacet name="lowerPanel" />
...
</cc:implementation>
#FacesComponent("entityDetailPanelComposite")
public class EntityDetailPanelComposite extends UINamingContainer {
public void init() {
UIComponent lowerPanel = getFacets().get("lowerPanel");
ValueExpression renderLowerPanel = getValueExpression("renderLowerPanel");
if (renderLowerPanel != null) {
lowerPanel.setValueExpression("rendered", renderLowerPanel); // It's an EL expression.
} else {
lowerPanel.getAttributes().put("rendered", getAttributes().get("renderLowerPanel")); // It's a literal value, or the default value.
}
}
}
This has the additional benefit you can specify it from client on.
<my:entityDetailPanel ... renderLowerPanel="true" />

submit all form on the same page [duplicate]

I am using the Facelet Templating Technology to layout my page in a JSF 2 app that I am working on.
In my header.xhtml, primefaces requires that menubar be enclosed in h:form.
<h:form>
<p:menubar autoSubmenuDisplay="true">
Menu Items here!
</p:menubar>
</h:form>
So, in my contents pages, I will have another h:form or more.
Will it just work if I just place the h:form in my template.xhtml?
<h:body>
<h:form>
<div id="top">
<ui:insert name="header"><ui:include src="sections/header.xhtml"/></ui:insert>
</div>
<div>
<div id="left">
<ui:insert name="sidebar"><ui:include src="sections/sidebar.xhtml"/></ui:insert>
</div>
<div id="content" class="left_content">
<ui:insert name="content">Content</ui:insert>
</div>
</div>
<div id="bottom">
<ui:insert name="footer"><ui:include src="sections/footer.xhtml"/></ui:insert>
</div>
<h:form>
</h:body>
I am actually thinking of a use case where I need multiple h:form in a page.
Thanks
You can safely use multiple forms in a JSF page. It's not different than when using plain HTML.
Nesting <form> elements is invalid in HTML. Since JSF just generates a bunch of HTML, it's not different in JSF. Nesting <h:form> is therefore also invalid in JSF.
<h:form>
...
<h:form> <!-- This is INVALID! -->
...
</h:form>
...
</h:form>
The browser behavior as to submitting a nested form is unspecified. It may or may not work the way you expect. It may for instance just refresh the page without invoking the bean action method. Even if you move the nested form (or a component that contains it) outside of the parent form with dom manipulation (or by e.g. using the PrimeFaces appendTo="#(body)"), it still won't work and there should be no nested forms at time of loading the page.
As to which forms you need to keep, having a single "god" <h:form> is actually a poor practice. So, you'd best remove the outer <h:form> from the master template and let the header, sidebar, content etc sections each define its own <h:form>. Multiple parallel forms is valid.
<h:form>
...
</h:form>
<h:form> <!-- This is valid. -->
...
</h:form>
Each form must have one clear responsibility. E.g. a login form, a search form, the main form, the dialog form, etc. You don't want to unnecessarily process all other forms/inputs, when you submit a certain form.
Note thus that when you submit a certain form, other forms are NOT processed. So, if you intend to process an input of another form anyway, then you've a design problem. Either put it in the same form or throw in some ugly JavaScript hacks to copy the needed information into a hidden field of the form containing the submit button.
Within a certain form, you can however use ajax to limit the processing of the inputs to a smaller subset. E.g. <f:ajax execute="#this"> will process (submit/convert/validate/invoke) only the current component and not others within the same form. This is usually to be used in use cases wherein other inputs within the same form need to be dynamically filled/rendered/toggled, e.g. dependent dropdown menus, autocomplete lists, selection tables, etc.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated - point 2
What is <f:ajax execute="#all"> really supposed to do? It POSTs only the enclosing form
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
<p:commandbutton> action doesn't work inside <p:dialog>
I was confounded by this issue for a while. Instead of a series of independent forms, I converted to a template, that is, rather than making a call to a xhtml with listed forms, usually as ui:include, I make a call to those formerly ui:included xhtml pages that ui:content captured in a parent template.

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

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>

f:param does not work with p:commandLink or h:commandLink on query string

f:param works great with h:link, but not with p:commandLink or h:commandLink.
For example, I have two pages test_first.xhtml and test_second.xhtml, and a backing java bean TestBean.java.
I start running test_first.xhtml.
If I click link1, which is a h:link, the page will redirect to test_second.xhtml. With the help of f:param, the address bar of the browser will show .../test_second.xhtml?id=1. On that page, testBean.userId gets printed.
If I click link2 or link3, the page redirects to test_second.xhtml. However, the address bar only shows .../test_second.xhtml, there is NO ?id=#! And testBean.userId does not get printed on that page.
How can I make commandLink work with f:param? Sometimes I want the link not to redirect to another page but to call some methods of bean depending on the data.
test_first.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head/>
<h:body>
<h:form>
<h:link value="link1" outcome="test_second" >
<f:param name="id" value="1"/>
</h:link>
<br/><br/>
<h:commandLink value="link2" action="test_second?faces-redirect=true" >
<f:param name="id" value="2" />
</h:commandLink>
<br/><br/>
<p:commandLink value="link3" action="test_second?faces-redirect=true">
<f:param name="id" value="3" />
</p:commandLink>
<br/><br/>
</h:form>
</h:body>
</html>
test_second.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<f:metadata>
<f:viewParam name="id" value="#{testBean.userId}" />
</f:metadata>
<h:head/>
<h:body>
<h:form>
This is the second page.
<h:outputText value="Selected id is #{testBean.userId}" />
<h:commandButton value="Print page id" action="#{testBean.print()}" />
</h:form>
</h:body>
</html>
TestBean.java
#ManagedBean
#SessionScoped
public class TestBean implements Serializable{
private Integer userId;
public void print() {
System.out.println(userId);
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
}
You misinterpreted the meaning of those two tags, namely <h:link> and <h:commandLink>, therefore, you also misinterpreted the meaning of <f:param> attached to either of the two. In anycase it is worthwhile to always read the documentation before asking the questions to get more insight.
<h:link> renders an HTML "a" anchor element. The value of the component is rendered as the anchor text and the outcome of the component is used to determine the target URL rendered in the "href" attribute. Any child UIParameter components are appended to the String to be output as the value of the "href" attribute as query parameters before rendering...
<h:commandLink> render an HTML "a" anchor element that acts like a form submit button* when clicked ... if the disabled attribute is not present, or its value is false. It renders "#" as the value of the "href" attribute, renders the current value of the component as the link text if it is specified and *renders JavaScript that is functionally equivalent to the following as the value of the "onclick" attribute:
document.forms['CLIENT_ID']['hiddenFieldName'].value='CLIENT_ID';
document.forms['CLIENT_ID']['PARAM1_NAME'].value='PARAM1_VALUE';
document.forms['CLIENT_ID']['PARAM2_NAME'].value='PARAM2_VALUE'; return false;
document.forms['CLIENT_ID'].submit()"
where hiddenFieldName is as described above, CLIENT_ID is the clientId of the UICommand component, PARAM_NAME and PARAM_VALUE are the names and values, respectively, of any nested UIParameter children.
In other words, within <h:link> tag nested <f:param> will end up as a query parameter of the generated URL, while within <h:commandLink> tag nested <f:param> will end up as a request parameter with a given value.
While the first one is clear, the second one deserves a better elaboration. To understand what it does, consider that if we abstract away from the details <h:commandLink> sends a POST request and attaches all nested <f:param> tags as request parameters. But it is up to you how you will handle them, as navigation is entirely in your hands.
So, the first option is to set a hardcoded action attribute, which use case is dubious, like in action="second-page", in which way you didn't pass any query parameter at all. What will be done is POSTing to the same view and forwarding to the second without undertaking any action. Quite a dumb action.
The second option is to specify an action method, like in action="#{bean.action}". In this case you must handle navigation in the provided action method, i.e. return null/void from the method for a postback, or return a navigation case outcome as a string to make a forward to the specified view. As for the request parameters that you passed with <f:param> they will be available with standard JSF means like #ManagedProperty("#{param.name}") on a request-scoped bean, or by calling ExternalContext#getRequestParameterMap() in any-scoped bean, for example, in action method, like in String param = externalContext.getRequestParameterMap().get("name"). So now you have your parameter in action method that you're free to use how you like, just adhere to a set of rules that exist for URLs.
Two things left worth mentioning. Remember that request parameters passed with calling the command link will be available only within that same request, as you might expect it to survive a faces-redirect=true that basically fires another request. The other option is to specify includeviewparams=true to pass through the paramaters of the current view, if that's desired, as mentioned in the other answer.
You could do it by concatenating the parameters with & directly at the action attribute:
<p:commandLink value="link3" action="test_second?faces-redirect=true&id=3"/>
Update 1
You might also consider to add &includeViewParams=true. This way view parameters of your target navigation will be included automatically.

What should be the scope of forms when using ui:include?

In a situation where a number of sub-pages will be included using ui:include where should the h:form tag go?
The form should be in the parent (A.xhtml and B.xhtml)?
A.xhtml excerpt
<h:form>
<ui:include src="B.xhtml" />
<ui:include src="other.xhtml" />
</h:form>
B.xhtml exerpt
<ui:composition>
tag contents here
</ui:composition>
The form should be in each child (C.xhtml and D.xhtml)?
C.xhtml excerpt
<ui:include src="D.xhtml" />
<ui:include src="other.xhtml" />
D.xhtml excerpt
<ui:composition>
<h:form>
</h:form>
</ui:composition>
Bonus internet points if you can elaborate on how this works with the Richfaces variation of form and in the first example how regions might be used to isolate each sub-file.
Also, is nesting forms a possibility? It would be like having A.xhtml use D.xhtml.
The first thing is you can't nest forms. Otherwise it depends heavily on your page structure, logic and action buttons/links placement.
When action is triggered it will submit to the server content of the form it is contained in. Therefore it is good when form content corresponds to some business entity which makes sense to be sent together. An extreme approach is to create a single form for the entire page. It will submit all of your inputs at each user interaction. It may make sense in some cases but if your page contains several logically distinct areas I would rather make them into separate forms.
I don't think any extra rules apply when using ui:include, this is one of the possible composition techniques while form layout seems more business structure driven.

Resources