3

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.

Steve
  • 541
  • 5
  • 7

1 Answers1

1

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;
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Would a session scope be appropriate here? – KidTempo Jan 27 '13 at 16:36
  • @Kid: depends on the concrete functional requirement. In OP's case, it likely is not. For more detail as to choosing the right scope, see also http://stackoverflow.com/questions/7031885/how-to-choose-the-right-bean-scope – BalusC Jan 27 '13 at 16:54