Implementing a return navigation in JSF - jsf

I am looking for a JSF coding practice that will allow one page to link to another that, when it completes, will return to the original page. So I have a page viewDoc.xhtml that has this:
<f:metadata>
<f:viewParam name="id" value="#{viewDoc.id}" />
</f:metadata>
( bunch of stuff to show the document indicated by "id" )
<p:button value="Edit Name/Title"
outcome="editnametitle">
<f:param name="id" value="#{param.id}" />
</p:button>
Then I have a page editnametitle.xhtml that has this:
<h:form>
(input fields and stuff)
<p:commandButton value="Save Changes"
action="#{editNameTitle.doSave()}"
/>
<p:commandButton value="Cancel"
action="#{editNameTitle.doCancel()}"
immediate="true"
/>
</h:form>
So how do I implement the backing bean methods doSave() and doCancel() such that when they finish they navigate back to viewDoc.xhtml with the id parameter of the document included?
I haven't found any guidance for a solution and I haven't been happy with any approach I have thought of so far. I have thought of something like adding to the p:button the return path like:
<p:button value="Edit Name/Title"
outcome="editnametitle">
<f:param name="id" value="#{param.id}" />
<f:param name="returnoutcome" value="viewDoc" />
</p:button>
Is this the right approach? Or is there some JSF facility that does this that I missed?

Yes, that's basically it if those requests are idempotent.
One possible improvement is that you can dynamically obtain the current view ID as below:
<f:param name="returnoutcome" value="#{view.viewId}" />
This allows abstracting away it in a reusable custom tag.
Personally I'd use parameter name "from" too as that's more short.

Related

<h:commandButton> is not refreshing page after actioned

hi we are using along with a4j tag.
here we are retrieving data from database after a click of button. even though the data is available in server, it will not display over view. After manual refresh of web page will lead to data diplay.
here is code snippet
.... some code here
<rich:tab id="menu5" label="Recall">
<ui:include src="/pages/mctrans/reCallMcifTrans.xhtml" />
</rich:tab>
reCallMcifTrans.xhtml contains below code
<h:commandButton type="button" id="reCallbutton1" value=" Search "
styleClass="commandExButton">
<a4j:support event="onclick" id="ajsf12"
oncomplete="javascript:alert('Search Completed');javascript:document.body.style.cursor='default';"
action="#{mcifRecallTransBean.reCallSearch}" reRender="reCallgrid1" />
</h:commandButton>
It looks like you're working with RichFaces 3.3. So, you don't need a <h:commandButton with <a4j:support> because you can use <a4j:commandButton> that already does this. You can refactor your code to this:
<a4j:commandButton type="button" id="reCallbutton1" value="Search"
styleClass="commandExButton"
action="#{mcifRecallTransBean.reCallSearch}"
reRender="reCallgrid1"
oncomplete="javascript:alert('Search Completed');javascript:document.body.style.cursor='default';" />
Make sure your reCallgrid1 component is available in the same <h:form> of the <a4j:commandButton>.
Since you also want to add a Wait while searching the data behavior when the button is clicked, you can use <a4j:status> along with the <a4j:commandButton> as shown in the <a4j:status> demo. Here's a basic example:
<a4j:commandButton type="button" id="reCallbutton1" value="Search"
styleClass="commandExButton"
action="#{mcifRecallTransBean.reCallSearch}"
reRender="reCallgrid1" />
<!-- Note that there's no oncomplete in this case -->
<a4j:status for="reCallbutton1">
<f:facet name="start">
<h:graphicImage value="/res/images/wait.gif"/>
</f:facet>
</a4j:status>
At last but not least, you should switch your managed bean to request scope and use RichFaces powerful <a4j:keepAlive> in order to simulate JSF 2 #ViewScoped. You can even use it in form of annotation on your managed bean (no additional configuration):
#KeepAlive
public class McifRecallTransBean {
//managed bean code here...
}
When you are using request parameters inside the bean, you need to pass them again with your action :
<h:commandButton type="button" id="reCallbutton1" value="Search" styleClass="commandExButton">
<a4j:support event="onclick" id="ajsf12" oncomplete="javascript:alert('Search Completed');javascript:document.body.style.cursor='default';" action="#{mcifRecallTransBean.reCallSearch}" reRender="reCallgrid1" />
<f:param name="param1" value="#{param['param1']}" />
<f:param name="param2" value="#{param['param2']}" />
</h:commandButton>

Cancel button doesn't work in case of validation error

i have a form with some inputs that have validation (required=true)
and when i click on the cancel button in case of validation error, the cancel button doesn't navigate to previous page, instead it removes the validation error (i think it goes back one step that was before the validation error ?)
here's my code:
<h:form>
<h:inputText value="#{myBean.nickName}" id="nickname" required="true"
requiredMessage="nickname should be specified" />
<h:commandLink immediate="true" id="cancel_link" onclick="history.back(); return false" style="float: left;margin: 118px 189px 0 0;">
<h:graphicImage width="90" height="28" value="#{resource['images:blu_btnCancel.png']}" />
</h:commandLink>
</h:form>
please advise how to fix that.
The JavaScript history.back() function takes you to the previous synchronous request, not to the previous view as you seemed to expect.
Even though the history.back() is terrible this way (unreliable, hackable, etc), a quick fix would be to send an ajax request on form submit instead of a synchronous request.
<h:form>
...
<h:commandButton value="submit">
<f:ajax execute="#form" render="#form" />
</h:commandButton>
</h:form>
Ajax requests doesn't account as browser history.
A more robust way is to just pass the identifier of the previous view along during navigation and then use <h:link> to link back to it. E.g.
<h:link value="Go to next view" outcome="nextview">
<f:param name="from" value="#{view.viewId}" />
<h:link>
And then in the nextview.xhtml
<f:metadata>
<f:viewParam name="from" />
</f:metadata>
...
<h:link ... outcome="#{from}" rendered="#{not empty from}">
<h:graphicImage ... />
</h:link>
If you're navigating by POST, you might consider using the flash scope to remember the initial view.
Unrelated to the concrete problem, the proper way to use <h:graphicImage> with JSF2 resources is to just use its name attribute instead of its value attribute with a #{resource} which is plain clumsy.
Replace
<h:graphicImage width="90" height="28" value="#{resource['images:blu_btnCancel.png']}" />
by
<h:graphicImage name="images/blu_btnCancel.png" width="90" height="28" />
Note that the library name images is here just replaced by the path name. The usage of the name "images" as library name is highly questionable. See also What is the JSF resource library for and how should it be used?

How to create an EL-Reference pointing to a Resource in JSF

I am currently using something like this in a composite component to create an EL-Reference to a resource:
<composite:implementation>
<ui:param name="resourceName" value="images:#{cc.resourceName}" />
<h:commandButton id="button" image="#{resource[resourceName]}" />
</composite:implementation>
As you can see, ui:param refers to a method named getResourceName() in the component class. This method determines which resource to load.
I would like to have a solution where the whole ui:param thing is unneccessary, something like:
<composite:implementation>
<h:commandButton id="button" image="#{cc.resource}" />
</composite:implementation>
Currently I don't even know if this is possible.
Any ideas?
Thx,
DS
If you do not want to use Resource API provided by JSF then you can just pass the context relative url to the image,
For example:
If this is your custom component:
<util:mbt actionMethod="#{bean.show}" resourceName="#{bean.img}" />
change it to:
<util:mbt actionMethod="#{bean.show}" resource="#{bean.img}" />
where bean.getImg() returns a String "/resources/images/test.jpg"
Alternatively, use resource API when adding the component like this:
<ui:param name="resourceName" value="images:#{bean.img}" />
<util:mbt actionMethod="#{bean.show}" resource="#{resource[resourceName]}" />
and use it like this:
<composite:implementation>
.....
<h:commandButton id="button" action="#{cc.attrs.actionMethod}" image="#{cc.attrs.resource}" />
.....
</composite:implementation>
The question still remains in my mind. "But why?"

h:outputLink navigation sometimes does not work

I have a navigation define from one page to another like this.
<h:outputLink id="idLink" value="Page1.seam" >
<f:param name="m" value="n103" />
<f:param name="mss" value="110" />
<h:outputText value="Return to Page 1" />
<a4j:support event="onclick" action="#{beanName.action}" limitToList="true" ignoreDupResponses="true" eventsQueue="que" ajaxSingle="true" immediate="true">
</a4j:support>
</h:outputLink>
The problem is there are sometimes that the view isn't changing to Page1.seam and remain in Page2.seam.
Is there anyone who knows better ?
Help will be greatly appreciated.
Thanks.
This construct makes no sense. Make it a normal link
<h:outputLink value="Page1.seam">
<f:param name="m" value="n103" />
<f:param name="mss" value="110" />
<h:outputText value="Return to Page 1" />
</h:outputLink>
and to invoke an action on opening of the page, use <f:event type="preRenderView"> in the target view instead.
<f:event type="preRenderView" listener="#{beanName.action}" />
See also:
How to execute action on GET request with f:viewParam?
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?

How to parameterize an a4j:commandLink properly?

I have the following problem: I need to redirect from a "list page" to a details page, but I need the id from the list. "record" in this example is the var attribute of a rich:dataTable. First of all I thought about this:
<a4j:commandLink id="detailsLink" value="show details" execute="#this" action="/customerDetails?faces-redirect=true&cusid=#{record.id}" />
But this is invalid syntax, so I tried something like this:
<a4j:commandLink id="detailsLink" value="show details" execute="#this" action="/customerDetails?faces-redirect=true">
<f:attribute name="cusid" value="#{record.id}"/>
</a4j:commandLink>
(I even tried f:param)
On the target page I tried to receive the value with...
<f:metadata>
<f:viewParam required="false" name="cusid" value="#{customerBean.editCustomer}"/>
</f:metadata>
Basically f:metadata works, because when I try it with the following hard coded parameter, I receive its value:
<a4j:commandLink id="detailsLink" value="show details" execute="#this" action="/customerDetails?faces-redirect=true&cusid=120" />
I found a solution, but I'm not sure if this is the right way:
In customerBean I make the following:
public String editCustomer(long customerId)
{
edit(customerId);
return "/customerDetails?faces-redirect=true";
}
But I don't think that this is the usual way to send and receive parameters with Rich Faces. Is there maybe a better solution?
The <a4j:commandLink> sends an ajax POST request while you need a normal GET request. Use <h:link> instead.
<h:link value="show details" outcome="/customerDetails?cusid=120" />
Here's the best way to do it. The example provided passes 2 parameters. You can have more than one. Just use the assignTo attribute and the value attribute. Hope this answers your question.
<a4j:commandLink action="#{myBackingBean.myAction}">
<a4j:param name="jobIdParam" value="#{job.jobNumber}"
assignTo="#{myBackingBean.jobId}" />
<a4j:param name="isDisplayedParam" value="true"
assignTo="#{myBackingBean.displayed}"/>
</a4j:commandLink>

Resources