Binding a JSF bean to a included JSF - jsf

I'm at the end of my rope with this one. I'm new to JSF so this is probably my misunderstanding of a lot of stuff.
<ui:composition>
<f:view>
<tr:form>
<ui:fragment rendered="#{param['type'] eq 'myType'}">
<ui:include src="/home/myPage.jspx" />
</ui:fragment>
......
I pass the page a certain type, it display's certain fields/criteria for a form and a bean backs it all because there is a single search.
Within myPage.jspx I have:
action="#{MyBean.submitForm}"
does not work, although a onsubmit="alert('hi');" does work as an attribute of the form element.
I guess what's most confusing is that
valueChangeListener="#{MyBean.stateChanged}"
does work on a field in the myPage.jspx
Why does the action (attribute of a button) not work?

During processing of the form submit, if the button or one of its parent components is not rendered, then the button's action won't be invoked. You need to make sure that the rendered attribute evaluates the same during processing of the form submit as it did when the form was displayed. In your case, you're depending on the value of a request parameter with the name type.
In this particular case, you could solve the problem by retaining the request parameter type by a <f:param> nested in the command button:
<h:commandButton ...>
<f:param name="type" value="#{param.type}" />
</h:commandButton>
Or, if you're using JSF 2.0, placing the bean in the view scope and setting the type parameter in the managed bean by <f:viewParam> can also solve it.
<f:metadata>
<f:viewParam name="type" value="#{bean.type}" />
</f:metadata>
...
<ui:fragment rendered="#{bean.type eq 'myType'}">
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated

Related

Setting f:setPropertyActionListener value with a f:param value

I'm trying to use the setPropertyActionListener tag to set a value in my backing bean. However, it doesn't work as I expected.
Context: userService is an instance of my backing bean, which contains an int member, reqID. This, in turn, is the key to a map of objects that belong to a class called User. I'm trying to create a page that will list all instances of User, and provide a button to visit a separate view that shows that particular User's information. To do this, I'm attempting to set userService.reqID to the id of the chosen User so it can generate a reference to that user for the next view (which is done in the call userService.toUserInfo).
If I use the xhtml snippet below:
<ui:define name="content">
<h:form>
<h:panelGrid>
<ui:repeat value="#{userService.UserList.getUserList()}" var="user">
<li>
<h:outputText value="#{user.name}" />
<h:commandButton value="View details of #{user.name}" action="#{userService.toUserInfo}">
<f:param name="id" value="#{user.id}" />
<f:setPropertyActionListener target="#{userService.reqID}" value="#{id}"/>
</h:commandButton>
</li>
</ui:repeat>
</h:panelGrid>
</h:form>
</ui:define>
The tag does not appear to evaluate id correctly and I get a Null Pointer Exception.
Earlier, I tried changing my setPropertyActionListenerTag so it read out as:
<f:setPropertyActionListener target="#{userService.reqID}" value="id"/>
which gave me an error, because the tag was sending the string "id" as opposed to the int value of the parameter.
Is there some way to force f:setPropertyActionListener to evaluate the expression under value? Or is there another tag that will allow me to do this?
Also, is ui:param used appropriately here?
The <f:param> (and <ui:param>) doesn't work that way. The <f:param> is intented to add HTTP request parameters to outcome of <h:xxxLink> and <h:xxxButton> components, and to parameterize the message format in <h:outputFormat>. The <ui:param> is intented to pass Facelet context parameters to <ui:include>, <ui:decorate> and <ui:define>. Mojarra had the bug that it also behaves like <c:set> without a scope. This is not the intented usage.
Just use <c:set> without a scope if it's absolutely necessary to "alias" a (long) EL expression.
<c:set var="id" value="#{user.id}" />
Put it outside the <h:commandLink> though. Also in this construct, it's kind of weird. It doesn't make the code better. I'd just leave out it.
<f:setPropertyActionListener ... value="#{user.id}" />
See also:
Setting ui:param conditionally
what is the scope of <ui:param> in JSF?
Defining and reusing an EL variable in JSF page
Unrelated to the concrete problem, if you're using EL 2.2 (as you're using JSF 2.2, you undoubtedly are as it requires a minimum of Servlet 3.0, which goes hand in hand with EL 2.2), then just pass it as bean action method argument without <f:setPropertyActionListener> mess. See also a.o. Invoke direct methods or methods with arguments / variables / parameters in EL and How can I pass selected row to commandLink inside dataTable?
<h:commandButton ... action="#{userService.toUserInfo(user.id)}">
On again another unrelated note, such a "View user" or "Edit user" request is usually idempotent. You'd better use <h:link> (yes, with <f:param>) for this. See also a.o. Creating master-detail pages for entities, how to link them and which bean scope to choose and How to navigate in JSF? How to make URL reflect current page (and not previous one).
Oh, that <h:panelGrid> around the <ui:repeat><li> doesn't make sense in HTML perspective. Get rid of it and use <ul> instead. See also HTMLDog HTML Beginner tutorial.

Conditionally rendering an <ui:include>

I am trying to toggle a page that shows a <rich:dataTable>. Before I just included the <ui:include> template and it would just show the table the whole time.
<ui:include src="../log/viewDlg.xhtml"/>
Now I want to be able to toggle it on/off on the web-page. Showing on the page with maybe a button or link. How can I achieve it?
Update 1: I am unable to get it to show up for some odd reason, Here is what I wrote so far based on feed back
View:
<a4j:commandLink value="View"
action="#{bean.showview}" render="viewPanel"/>
<h:panelGroup id="viewPanel">
<h:panelGroup id="tableRenderPanel" rendered="#{bean.showPolicyView}">
<ui:include src="../log/viewDlg.xhtml"/>
</h:panelGroup>
</h:panelGroup>
Backing bean:
private boolean showPolicyView = false;
public void showView() {
showPolicyView = !showPolicyView;
}
public boolean isShowPolicyView(){
return showPolicyView;
}
Wrap your <ui:include> inside two <h:panelGroup> elements. There's a catch here, you can't rerender a conditional component. Why's this? because when the element's rendered attribute resolves to false, it will not be considered while rendering the view so it can't be the target of an operation (in this case, related to renderization).
Jumping to the code, you'll have this:
<h:panelGroup id="wrapperPanel">
<h:panelGroup id="tableRenderPanel" rendered="#{yourBean.renderTable}">
<ui:include src="../log/viewDlg.xhtml"/>
</h:panelGroup>
</h:panelGroup>
yourBean#renderTable is a Boolean property that determines if the component will be rendered. When it evaluates to false, the component is not included in the component tree.
Toggling the view
To toggle the view, simply create a bean method that either refreshes the page
<h:commandLink action="#{yourBean.toggleTableView}"/>
or the particular panel through AJAX. To do this in JSF 1.2, rely on extensions like RichFaces to introduce AJAX, if you can. For example, should you choose RichFaces, you can use <a4j:commandLink/> and its handy render (or reRender in older versions) attribute to achieve what you could do normally with an <f:ajax/> in JSF 2
<a4j:commandLink action="#{yourBean.toggleTableView}" reRender="wrapperPannel"/>
Or, another alternative is
<a4j:commandLink action="#{yourBean.toggleTableView}">
<a4j:support event="oncomplete" reRender="wrapperPannel"/>
</a4j:commandLink>
Please note that the reRender attribute may vary depending on the structure of your page, but it should always reference the id of the wrapping panel in the end. Also, reRender was renamed to simply render in late RichFaces versions.
So, assuming you have a renderTable property (getter + setter) in yourBean, the toggleTableView must change it, in order to dinamically define if the component is to be rendered or not (renderTable = false).
Introducing RichFaces
Check this link for help in setting up RichFaces in your project.
I like the use of ui:include better than inserting h:panelBoxes like here:
<ui:fragment rendered="#{myBean.yourCondition()}">
<ui:include src="viewA.xhtml"/>
</ui:fragment>
<ui:fragment rendered="#{not myBean.yourCondition()}">
<ui:include src="viewB.xhtml"/>
</ui:fragment>
Advantage: Tag handlers do not represent components and never become a part of the component tree once the view has been built. It won't interefere with your CSS - the h:panelBox, in contrary, inserts a div or span.
... Another approach would be c:choose, which works but can cause render phases issues.
<c:choose>
<c:when test="#{myBean.yourCondition()}">
<ui:include src="viewA.xhtml"/>
</c:when>
<c:otherwise>
<ui:include src="viewB.xhtml"/>
</c:otherwise>
</c:choose>
Caution: When fiddling with tag handlers (like any c:xxx), be sure to know the difference between UI Components and Tag Handlers. Namely that UI Components and Tag Handlers are renderend in different phases. That implies that you cannot create a variable in a composite component and use it in a nested tag handler. c:choose and ui:include are both tag handlers, so normally it's not a problem. Read the link, it's a very short example and very insightful.

Pass an input value directly as action method argument

Is there a way to do pass an input value as a action's parameter without using managed properties?
i.e.
<h:form>
<h:inputText id="input" />
<h:commandButton action="#{someBean.doSome(input)}" />
</h:form>
Yes, it's during the form submit already there in the JSF component state. Just bind the input component to the view by binding attribute, which will reference an UIInput instance, which in turn has a getValue() method for the very purpose of retrieving the input value (so that you can pass it as action method argument):
<h:form>
<h:inputText ... binding="#{input}" />
<h:commandButton ... action="#{someBean.doSome(input.value)}" />
</h:form>
The properness of this approach is however highly questionable and depends on concrete functional requirements. This approach is namely basically tight-coupling the view with the model and therefore considered a bad practice.
See also:
How to send form input values and invoke a method in JSF bean
How does the 'binding' attribute work in JSF? When and how should it be used?

Command Button inside composition page in JSF

I have the same problem as user1598186 has stated in his question here : p:commandButton doesn't call bean's method in an <ui:include> page
However, no solution has been given (he has removed <ui:include> tags altogether and used variables instead)
Are there any ways of using <ui:include> and still have my backing bean's method executed, when I'm calling it inside the commandButton.
Any help will be much appreciated.
EL 2.2 method parameters (so, #{bean.method()} instead of #{bean.method}) can be used to pass a method signature that can be used in the actionListener attribute of a commandButton. The following is an example of passing a ManagedBean property as well as passing a method signature:
Main Page
<ui:include src="/jointeam.xhtml">
<ui:param name="propertyValue" value="#{managedBean.property1} />
<ui:param name="method" value="#{managedBean.performAction()}" />
</ui:include>
jointeam.xhtml
...
<h:inputText value="#{propertyValue}" />
...
<p:commandButton value="Submit" actionListener="#{method}" />
You can see how powerful this is in terms of code reuse and for many instances is less verbose and easier to use than composite components.

How to access ui:param value in the managed bean

I have seen this question ask around a lots, however, none was properly answered so I decided to ask again. So if I have this: if I am in A.xhtml and I
<ui:include src="B.xhtml">
<ui:param name="formId" value="awesome Id"/>
</ui:include>
so in B.xhtml, I can do this
<h:outputText value="#{formId}"/>
when I run A.xhtml, I would see awesome Id get printed on the screen. However how do I access the value of formId in the backing bean. I look inside FacesContext.getCurrentInstance().getAttributes() and FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap() and I just cannot seems to locate it. To go a bit further, so I try:
Inside B.xhtml, I now have
<h:inputHidden id="hiddenFormId" value="#{formId}"/>
<h:outputText value="#{formId}"/>
the idea is that I can access the value of formId in the RequestParameterMap under key hiddenFormId. But now if I have:
<h:form id="myForm">
<ui:include src="B.xhtml">
<ui:param name="formId" value="awesome Id"/>
</ui:include>
<a4j:commandButton render="myForm" value="My Button"/>
</h:form>
then I would get this erro if I look inside the POST request (when inside chrome or ff debug mode)
<partial-response><error><error-name>class javax.faces.component.UpdateModelException</error-name><error-message><![CDATA[/B.xhtml #9,61 value="${formId}": /index.xhtml #27,61 value="awesome Id": Illegal Syntax for Set Operation]]></error-message></error></partial-response>
so How to access ui:param value in the managed bean?
Where the <ui:param> is under the covers stored is actually implementation dependent. In Mojarra it's stored as an attribute of the FaceletContext and thus available in your backing bean as follows:
FaceletContext faceletContext = (FaceletContext) FacesContext.getCurrentInstance().getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
String formId = (String) faceletContext.getAttribute("formId");
Whether the value would be available is however subject to timing. If your backing code is running while executing the rendering of the include, then it'll be available, else it'll be null.
I recall that MyFaces does it a bit differently, but I don't recall the details anymore and I don't have its source at hand right now.
As to your <h:inputHidden> attempt, the <h:inputHidden> isn't well suited for the sole purpose of passing view-definied hidden parameters along with the form submit. Just use plain HTML instead.
<input type="hidden" name="hiddenFormId" value="#{formId}" />
It'll be available as a request parameter with exactly this name.

Resources