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

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.

Related

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

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.

Include same code segment from another file at multiple places of single Facelet and render dyncamically [duplicate]

I know we can't repeat the ID of any component we have in the same view tree.
I have a page which includes another pages by certain condition Like this...
<h:panelGroup rendered="#{bean.insertMode == 'SINGLE'}">
<ui:include src="_single.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{bean.insertMode == 'DOUBLE'}">
<ui:include src="_double.xhtml" />
</h:panelGroup>
Now In these pages I have "Almost" the same components hierarchy (Complex) with different actions behaviour (Not only method calls, also view), for example:
_single.xhtml
<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.singleAction()}" />
_double.xhtml
<p:inputText id="fieldID" value="#{bean.value}" />
<p:commandLink actionListener="#{bean.doubleAction()}" />
My little example works fine, and renders as it supposed to, but I get
java.lang.IllegalStateException: Component ID fieldID has already been found in the view.
I know that JSF process the full pages even if they are not included and that's why I'm getting this exception.
Any smart way to solve this without changing the IDs of the components inside the include pages (Although it works, but the exception is annoying and seems something is wrong). I don't want also to wrap each one of the pages with some container component with a different ID so they would have a different FULL ID like formId:fieldID because the master page is also referring to these components inside these includes!
The duplicate component ID error occurs because the both includes physically end up in the JSF component tree. The <h:panelGroup rendered="false"> doesn't prevent them from ending up in JSF component tree, instead it prevents them from generating their HTML output.
Instead of conditionally rendering their HTML output, you need to conditionally build them in the JSF component tree. JSTL is very helpful in this as it runs during view build time:
<c:if test="#{bean.insertMode eq 'SINGLE'}">
<ui:include src="_single.xhtml" />
</c:if>
<c:if test="#{bean.insertMode eq 'DOUBLE'}">
<ui:include src="_double.xhtml" />
</c:if>
In case you're using Mojarra, you only need to make sure you use at least version 2.1.18 or newer, otherwise view scoped beans will behave like request scoped beans.
An alternative is to make use of EL conditional operator in src attribute (the <ui:include> itself runs as being a taghandler also during view build time):
<ui:include src="_#{bean.insertMode eq 'SINGLE' ? 'single' : 'double'}.xhtml" />
Or even use the insertMode directly as filename:
<ui:include src="_#{fn:toLowerCase(bean.insertMode)}.xhtml" />
Either way, you need to make absolutely sure that the #{bean.insertMode} is available during view build time, and also that exactly the same value is available during the restore view phase of postbacks as it was during initial render, otherwise the view would possibly be restored with the wrong include and JSF can't decode the right inputs and command anymore. Also, when you want to change the include during postback, you really need to rebuild the view (return non-null/void), or to send a redirect.
See also:
JSTL in JSF2 Facelets... makes sense?

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 ensure an active conversation in JSF2?

We have a JSF2 based web application which models a purchase process, where the user enters and selects different information in a wizard-like manor, can navigate forward and backward and at some point finishes the process.
So nothing special, a typical conversation between the application and the user. For that I tried both the regular and the MyFaces conversation scope, but although I know how to begin and end a conversation. I still don't manage to ensure an active conversation, so in other words how do I avoid a user entering the process in the middle by typing the pages URL and instead of that redirecting him to step 1?
You can't avoid that. The enduser has full freedom over manipulating the request URL. Your best bet would be to stick to a single view/URL wherein the wizard steps are conditionally (ajax-)rendered based on the state of the view. This way the enduser can only navigate by the buttons provided in the UI and not by manipulating the URL.
E.g.
<h:panelGroup rendered="#{wizard.step == 1}">
<ui:include src="/WEB-INF/wizard/step1.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 2}">
<ui:include src="/WEB-INF/wizard/step2.xhtml" />
</h:panelGroup>
<h:panelGroup rendered="#{wizard.step == 3}">
<ui:include src="/WEB-INF/wizard/step3.xhtml" />
</h:panelGroup>
Also, this way you can get away with a single #ViewScoped bean instead of a #ConversationScoped one (with MyFaces CODI you would be able to use JSF #ViewScoped on a CDI #Named, for the case that is important).
Further, PrimeFaces has a <p:wizard> component which does almost exactly like that. You may find it useful in order to save yourself from some painful boilerplate code as to validation and such.

JSF dynamic ui:include

In my app I have tutor and student as roles of user. And I decide that main page for both will be the same. But menu will be different for tutors and users. I made to .xhtml page tutorMenu.xhtml and student.xhtml. And want in dependecy from role include menu. For whole page I use layout and just in every page change content "content part" in ui:composition.
In menu.xhtml
<h:body>
<ui:composition>
<div class="menu_header">
<h2>
<h:outputText value="#{msg['menu.title']}" />
</h2>
</div>
<div class="menu_content">
<с:if test="#{authenticationBean.user.role.roleId eq '2'}">
<ui:include src="/pages/content/body/student/studentMenu.xhtml"/>
</с:if>
<с:if test= "#{authenticationBean.user.role.roleId eq '1'}">
<ui:include src="/pages/content/body/tutor/tutorMenu.xhtml" />
</с:if>
</div>
</ui:composition>
I know that using jstl my be not better solution but I can't find other. What is the best decision of my problem?
Using jstl-tags in this case is perfectly fine, since Facelets has a corresponding tag handlers (that are processed in the time of view tree creation) for the jstl tags and handles them perfectly. In this case c:if could prevent processing (and adding the components located in the included xhtml file) of the ui:include which leads to reduced component tree and better performance of the form.
One downside of using this approach is that you cannot update these form parts using ajax, i.e. you change the user role and refresh the form using ajax, because the ui:include for the other role is not part of the view anymore. In such case you have to perform a full page refresh.

Resources