tags:

views:

474

answers:

2

I'm somewhat confused about the lifecycle of ManagedBeans of type "request".

In this example i'm using one request bean "userBean" to fill this page and one request bean "userEditBean" to fill the following edit page.

<h:form>
    <h:panelGrid border="1" columns="2">

        <h:outputText value="Name" />
        <h:outputText value="#{userBean.user.name}" />
        ...
    </h:panelGrid>

    <h:commandButton value="Edit" action="edit" actionListener="#{userEditBean.init}">
        <f:attribute name="user" value="#{userBean.user}"/>
    </h:commandButton>
</h:form>

When i press the Edit button a userEditBean is created but the attribute map resolves "user" to null.

Does this mean that the attribute EL is resolved after the userBean has already been destroyed? How can i pass values from incoming beans to outgoing beans?

A: 

request scope means the bean lives during one request. And you fill your edit page (1st request), and send the edited user (2nd request).

In addition to that, <f:attribute> sets tha attributes in the parent component, not in the request. So in your code the attributes will be found in the button.getAttributes() (if you have bound your button).

Furthermore, it is strange to have an actionListener method named init. Since you don't need the event, you can set the action to be the method which will do the editing operation, and make that method return the nagivation-rule you want.

Bozho
yes, but button.getAttributes() only seems to contain an EL expression. And at the time i try to resolve it (call to userEditBean.init) it resolves to null. What do i do about that?
Stroboskop
+1  A: 

You're setting the attribute value with an expression, not a static value. Whenever you request the value, the expression will be re-evaluated again. The userBean.user apparently isn't present in the subsequent request. You need to ensure that it is there (in other words, the constructor of the userBean should ensure that the user is been created and set.

There are however alternatives. One of the best is to use Tomahawk's <t:saveState> for that. Add it somewhere in the page:

<t:saveState value="#{userBean.user}" />

That said, I agree with Bozho that the whole approach is a bit strange, but that's another story. You may however get lot of useful ideas out either of the following articles: Communication in JSF and/or Using Datatables. Good luck.

BalusC
What is strange about having to pass incoming data on?
Stroboskop
Nothing, but just the way how you did it requires more work when using standard JSF components as you're trying to pass whole Java objects to the subsequent request while HTTP/HTML only takes and products Strings. But I understand what you want and the `t:saveState` is what you need. In the `UserEditBean` just access the `UserBean` (managed property injection?) to get its `user` property.
BalusC
Looks like t:saveState does what i want. And yet another Jar i need to include...
Stroboskop
Tomahawk has more advantages/enhancements over the standard components as well. I'll sum up the `t:dataList`, `t:inputFileUpload`, `t:dataTable preserveDataModel="true"`, `t:selectManyRadio layout="spread"`, etcetera. It are per saldo actually five JAR files, but you may already have some of those `commons` dependencies (`io`, `el`, `logging` and/or `fileupload`).
BalusC
You helped me do what i was looking for. But i guess i'm going to think of a different strategy, because i understand now that using t:saveState stores the full object i only need server side in the HTML page. I guess i'm going to use an ID and caches instead.
Stroboskop
The `t:saveState` stores the obejct in view state which in turn is by default stored in session scope. If you have "view state saving" configured to "client" instead of "server", then the entire view state will indeed be stored in a hidden input field in the HTML page. This "problem" (if you call it for some reasons) is thus not necessarily caused by `t:saveState`.
BalusC