data exchange using view scoped bean - jsf

Trying to wrap my head around using view scoped beans. Please forgive the length of my posting.
I have a view: page1.xhtml which uses a bean and a commandButton that submits the form, invokes a method of that same bean via the action attribute.
The return value of the method causes a navigation rule to 'navigate' to page2.xhtml. So it is my understanding that the bean named "player" used by page1.xhtml goes out of scope once navigation takes the request flow to page2.xhtml. After all, each view uses a view scoped bean named "player". I need to convey a parameter named id. So page1.xhtml has a element as a child element of the commandButton used to 'submit' page1'.
Page2.xhtml uses the following construct as I want the view scoped bean to be loaded prior to the rendering of page2.xhtml:
<ui:define name="metadata">
<f:metadata>
<f:viewParam name="id" value="#{player.id}" />
<!-- this should cause bean to be loaded before it's needed for initial rendering -->
<f:event type="preRenderView" listener="#{player.initFromId}"/>
</f:metadata>
</ui:define>
In the player.initFromId method, I dump out to stdout the keys & values of the map returned by FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
What do I see? [I chopped most of the client saved view state off from this listing :-)]
most of the keys are fully qualified UI component names, named with the component hierarchy naming as expected. Good. Typical POST nv pairs...
Finally my question: am I correct in assuming the key: id is there because of the f:param element as the child of the commandButton caused the commandButton's impl code to push the key+value into the request parameter map? I hope so but I don't like assuming too much. Almost always gets me deeper into trouble.
But the f:viewParam doesn't result in the player.setId() method being invoked prior to player.initFromId() - via the preRenderView event. player.initFromId() is invoked but not the setter??
I hope my assumption is right as I can't imagine it being a design goal to make use of the UI component field names by the code invoked by a different view/page (in this example, page2.xhtml). That would tightly couple the implementation of each page, making the externalized navigation rules practically pointless. I am also assuming that a goal of using the f:viewParam and f:param is to provide minimal coupling (only at the declarative level - page1 declares it provides a param, page2 declares a need for the param - protocol is left to the framework).
Player.initFromId - key:id, value:37
Player.initFromId - key:javax.faces.ViewState, value:H4sIAAAAAA[....]YQfAAA=
Player.initFromId - key:javax.faces.partial.ajax, value:true
Player.initFromId - key:javax.faces.partial.execute, value:#all
Player.initFromId - key:javax.faces.partial.render, value:registrationForm:regPage
Player.initFromId - key:javax.faces.source, value:registrationForm:SubmitButton
Player.initFromId - key:registrationForm, value:registrationForm
Player.initFromId - key:registrationForm:SubmitButton, value:registrationForm:SubmitButton
Player.initFromId - key:registrationForm:firstName, value:Bob
Player.initFromId - key:registrationForm:j_idt18:carriers, value:Sprint
Player.initFromId - key:registrationForm:j_idt18:city, value:Sparta-test4
Player.initFromId - key:registrationForm:j_idt18:dob_input, value:
[ many other UI components key+value pairs omitted]
from page1.xhtml:
<p:commandButton tabindex="0" id="SubmitButton" value="Register"
action="#{player.register}" update="regPage" >
<!-- this needs to be set after the register() method completes. is that so? -->
<f:param name="id" value="#{player.id}"/>
</p:commandButton>
Many thanks for taking the time to read this excessive posting.

You seem to be navigating by a forward. A forward basically creates a new view during render response phase. The <f:viewParam> doesn't run on a forwarded request. It runs on the initial request only (as originally fired by the client). You need to navigate by a redirect instead of a forward so that the client will be instructed to fire a brand new GET request, triggering all the <f:viewParam> works. You can achieve that by adding faces-redirect=true parameter to the navigation outcome like so:
return "page2?faces-redirect=true";
This however loses all request parameters of the current request. So you'd need to explicitly add it to the navigation outcome:
return "page2?faces-redirect=true&id=" + id;

Related

myfaces 2.1.17 - f:viewParam setter being called on commandlink [duplicate]

I'm using an <f:viewParam> to pass a parameter as follows.
<ui:define name="metaData">
<f:metadata>
<f:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
Is it possible to process this <f:viewParam>, only when the page is loaded/refreshed?
It is just because the converter as specified with the <f:viewParam> is costly that converts the value passed through the query-string to a JPA entity. Hence, it involves an expensive database transaction, even when doing ajaxical postbacks using components like <p:commandButton>, <p:commandLink> which is unnecessary.
So, when for example, a <p:commandLink> (ajaxical) is clicked, the expensive business service (in the converter) should not be executed. Can this be done?
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.
You can achieve this by creating a custom tag extending <f:viewParam> wherein you store the submitted value as an instance variable which isn't stored in JSF view state instead of in the JSF view state as the <f:viewParam> by default does. By end of request, all UI component instances are destroyed. They are recreated in beginning of the request. When submitted value is null, then it won't call the converter nor the model setter. This all is elaborated in Arjan Tijms' blog.
OmniFaces offers already since version 1.0 a ready to use solution in flavor of <o:viewParam>, see also my own blog on that. Based on your question history, you're already using OmniFaces, so all you basically need to do is to replace f: by o:.
<ui:define name="metaData">
<f:metadata>
<o:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
This won't call the model setter (nor the converter) during postbacks on the same view.
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.
That's because the <f:viewParam> is in essence an UIInput component (else it wouldn't be able to perform conversion, validation, model-update and all that stuff like usual input components) which is thus just an UIComponent supporting a rendered attribute. This is however not explicitly documented as it actually doesn't render anything to the HTML output (that's also why it's a f:xxx, not a h:xxx). But with this attribute you can actually control the behavior during postback as this attribute is also evaluated in processDecodes() method which is invoked during apply request values phase.

Process f:viewParam only on page load

I'm using an <f:viewParam> to pass a parameter as follows.
<ui:define name="metaData">
<f:metadata>
<f:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
Is it possible to process this <f:viewParam>, only when the page is loaded/refreshed?
It is just because the converter as specified with the <f:viewParam> is costly that converts the value passed through the query-string to a JPA entity. Hence, it involves an expensive database transaction, even when doing ajaxical postbacks using components like <p:commandButton>, <p:commandLink> which is unnecessary.
So, when for example, a <p:commandLink> (ajaxical) is clicked, the expensive business service (in the converter) should not be executed. Can this be done?
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.
You can achieve this by creating a custom tag extending <f:viewParam> wherein you store the submitted value as an instance variable which isn't stored in JSF view state instead of in the JSF view state as the <f:viewParam> by default does. By end of request, all UI component instances are destroyed. They are recreated in beginning of the request. When submitted value is null, then it won't call the converter nor the model setter. This all is elaborated in Arjan Tijms' blog.
OmniFaces offers already since version 1.0 a ready to use solution in flavor of <o:viewParam>, see also my own blog on that. Based on your question history, you're already using OmniFaces, so all you basically need to do is to replace f: by o:.
<ui:define name="metaData">
<f:metadata>
<o:viewParam name="id" value="#{bean.entity}" converter="#{converter}"/>
</f:metadata>
</ui:define>
This won't call the model setter (nor the converter) during postbacks on the same view.
This somehow works (strange enough nevertheless), when the rendered attribute is evaluated against facesContext.postback like rendered="#{not facesContext.postback}" but the attribute rendered is not documented. Hence, it is unreliable.
That's because the <f:viewParam> is in essence an UIInput component (else it wouldn't be able to perform conversion, validation, model-update and all that stuff like usual input components) which is thus just an UIComponent supporting a rendered attribute. This is however not explicitly documented as it actually doesn't render anything to the HTML output (that's also why it's a f:xxx, not a h:xxx). But with this attribute you can actually control the behavior during postback as this attribute is also evaluated in processDecodes() method which is invoked during apply request values phase.

Get url parameter into facelets view after user session timeout

I am building a CRUD web application using JSF. I have a problem with loading a page after the user session has timed out. That is i lose the parameters I need to construct the view (even though the parameters are still visible in the url like so: 'someurl/view.xhtml?pid=5'.
In the .xhtml file the parameter pid is used to load some content from an underlying database when constructing the view. When the user has been inactive for a while their session times out, and if they try to reload the page in the browser they are forwarded to the login page (the 'someurl/view.xhtml?pid=5' still intact) and on succesful login go back to the view.xhtml page where I wan't the view to be constructed as if their session had never timedout.
However this does not happen because the 'pid' parameter is no longer set in the view. But since the 'pid' parameter is still visible in the url I feel like I should be able to get it into the view and load the protein with this id from the database.
These are the things I've tried:
#{protein.setProteinById(param.pid)}
and
#{protein.setProteinById(param['pid'])}
and
#{protein.setProteinById(request.getParameter('pid'))}
and
<c:set value="${request.getParameter('pid')}" var="pid" />
#{protein.setProteinById(pid)}
Is this possible to do? Then how?
I'm no expert, but wouldn't you set it in the managed bean?
As far as I know there are two methods for doing this.
One method is using in your facelet to push a view parameter back into a bean (I have a scenario where this doesn't work because of other things, so have no experience with it)
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
I have a prerender method, which is always called before a render
<f:metadata>
<f:event type="preRenderView" listener="#{MyController.prerenderMethod}" />
</f:metadata>
And inside the method, I look at the parameters:
public void prerender(ComponentSystemEvent event) {
value = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("key");
}

commandLink is not fired in a page with a param in its URI

When I call a method in a page with a param in its URI, the method is not invoked unless I pass the parameters of the uri again. For example if I have:
http://maywebsite/myapp/mypage.xhtml?mykey=myvalue
This method results in error (obviously because it renders the page again without params, but the method foo is never invoked):
<h:commandLink value="Do Action" actionListener="#{mybean.foo}"/>
So I added an ajax to only update the component, but the button is not getting fired:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:ajax render="somecomponent"/>
</h:commandLink>
When I passed the param values again, the button invokes the method just fine:
<h:commandLink value="Do Action" actionListener="#{mybean.foo}">
<f:param name="mykey" value="myvalue"/>
<f:ajax render="somecomponent"/>
</h:commandLink>
However, this button is included (ui:include) in many pages with different param keys and values. How can I invoke the method without passing the param values?
Im using glassfish 3.1.2, jsf 2.0
Apparently the bean is request scoped and the parameter plays a role in the way how the command link is rendered (e.g. by the rendered attribute on one of its parent components, or by a dynamic include of the template containing the command link).
All those conditions are namely re-evaluated during apply request values phase of the form submit. The developer has to make sure that all those conditions are exactly the same as when the form was presented to the enduser. So, when the bean is request scoped and the parameter is absent, then the command link appears as non-rendered in the component tree and this way its action won't be invoked.
Putting the bean in the view scope is the easiest way to fix this (unless you're using a dynamic <ui:include>, this is then more complicated, you'd need to turn off partial state saving for the particular view).
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated - point 5

Modify dynamically JSF snippets by h:commandlink

I have a h:commandlink control in page1. the control uses f:ajax to call to the following h:panelgroup :
I have a h:panelgroup control in page2 (a snippet), which has a ui:include within it.
I have a h:panelgroup control in page3 (a snippet), which has a ui:include within it.
Now according to the choices made on page1, I would like to switch the snippets by clicking on the h:commandlink control.
I have a BIG problem there: it seems that only if I click twice on the commandlink, only then the snippet changes - and not on one click.
I have tried to remove the f:ajax to render the panelgroup, and still it does not work...
There are two potential causes of this problem.
The <f:ajax> is fully re-rendering another <h:form> than where it is sitting in. This way the view state of the other form will get lost which would require invoking the action on the other form twice before it really get executed.
The solution is to not re-render the other <h:form>, but only some container component in that form. E.g.
<h:form id="otherForm">
<h:panelGroup id="content">
...
<h:panelGroup>
</h:form>
with
<f:ajax render=":otherForm:content" />
When there's a rendered attribute on the <h:commandLink> or any of its parent components, then it must evaluate true during the apply request values phase of the postback request in order to get JSF to invoke the bean action associated with the <h:commandLink> during the invoke action phase of that request. Perhaps the bean is request scoped and/or some odd/illogical flow inside the bean caused that the rendered attribute is not properly been preserved.
Best is to maintain those rendered conditions in a #ViewScoped bean and let its action methods return void or null so that the bean lives as long as you're interacting with the same view. Change the rendered conditions during action methods only and not inside setters/getters or something.

Resources