tags:

views:

1044

answers:

1

I have two pages. Search page is the first page that takes user inputs. Second page shows the result set in datatable. Second page has 3 panel for resultset, update and create all in single page. Depending upon the which button being clicked, I am rendering panels true and false.

<h:panelGroup styleClass="panelGroup"
       id="resultSet" rendered="#{bean.truefalse1}">
.
.
</h:panelGroup

<h:panelGroup styleClass="panelGroup"
       id="updateForm" rendered="#{bean.truefalse2}">
.
.
</h:panelGroup


<h:panelGroup styleClass="panelGroup"
       id="createForm" rendered="#{bean.truefalse3}">
.
.
</h:panelGroup>

From the search page I am setting these create and update panels to false and displaying only resultset.After the row from the result set is clicked I am showing updateForm panel but keeping create panel to false.

But here the problem is, If there is validation error, then the property that was set from search page is being lost and all the panels are shown.

How do I get the value(boolean true or false) that was set from search page previously, since I am not navigating to different page.

I have getters and setters for boolean property in second class. I even tried keeping hidden fields(i.e the boolean property that was set from search page). Shouldn't all the submitted values be recovered after validation error. Or just the ones we type in the form.

What is the best solution?

Any help is highly appreciated!!!

+3  A: 

You indeed need to transfer the very same boolean properties to the next request. You can in theory use <h:inputHidden value="#{bean.boolean1}" /> for this, but unfortunately those will only be set during update model values phase, while you actually need it to be available during apply request values phase. Besides, they will also go lost when a validation error occurs.

There are three ways to fix this non-intuitive behaviour of h:inputHidden (I've ever filed a bug against it at the Mojarra issue list, but they didn't seem to do anything with it).

First is to use the binding on the h:inputHidden instead:

<h:inputHidden binding="#{bean.hidden1}" />

This however requires changes in the way you get/set the boolean values in the backing bean code. For example:

private HtmlInputHidden hidden1 = new HtmlInputHidden(); // +getter +setter.

public void setBoolean1(boolean boolean1) {
    hidden1.setValue(boolean1);
}

public boolean getBoolean1() {
    return (Boolean) hidden1.getValue();
}

Second is to use Tomahawk's t:saveState instead.

<t:saveState value="#{bean.boolean1}" />

The major advantage is that you don't need to change anything in the backing bean code. It will restore the value early before the apply request values phase. You only need to add extra libraries if not done yet, but as Tomahawk provides much more advantages than only the t:saveState, such as the in basic JSF implementation missing components/features t:inputFileUpload, t:dataList, t:dataTable preserveDataModel="true", t:selectOneRadio layout="spread" and so on, it is worth the effort.

The third way is to store them in a session scoped bean, but you actually don't want to do that for request scoped variables. It would only give "wtf?" experiences when the enduser has multiple tabs/windows open in the same session.

Edit: as per the comments, here's an SSCCE of the second way:

JSF page:

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;

<f:view>
    <html xmlns="http://www.w3.org/1999/xhtml"&gt;
        <head>
        </head>
        <body>
            <h:form id="form">
                <h:inputHidden binding="#{myBean.hidden}" converter="javax.faces.Boolean" />
                <h:commandButton value="submit" action="#{myBean.submit}"/>
                <h:outputText value="Current boolean value: #{myBean.hidden.value}" />
            </h:form>
        </body>
    </html>
</f:view>

MyBean class:

package mypackage;

import javax.faces.component.html.HtmlInputHidden;

public class MyBean {

    private HtmlInputHidden hidden = new HtmlInputHidden();

    public void submit() {
        if (hidden.getValue() == null) {
            hidden.setValue(true); // Set to true on 1st submit.
        } else {
            hidden.setValue(!((Boolean) hidden.getValue())); // Toggle true/false.
        }
    }

    public HtmlInputHidden getHidden() {
        return hidden;
    }

    public void setHidden(HtmlInputHidden hidden) {
        this.hidden = hidden;
    }

}

The relevant part of faces-config.xml:

<managed-bean>
    <managed-bean-name>myBean</managed-bean-name>
    <managed-bean-class>mypackage.MyBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Playground environment is JSF 1.2_13 on Tomcat 6.0.20.

BalusC
Great answer. (+1) BalusC, do you use RichFaces besides Tomahawk ? Is it a good idead to use RichFaces ?
Arthur Ronald F D Garcia
thanks balusC for your precious time...I will try and let you know, but for the second option I am using RSA 7.5.x so if I use tomahawk then it will be only for t:savestate and more over that I dont think it will support also. I had tried earlier but no success. thanks,
"This however requires changes in the way you get/set the boolean values in the backing bean code."What do you mean by this, are'nt they normal getters and setters, if not could you explain more... please.thanks.
@Arthur: I don't use RichFaces. But if you already use it, you can also use its `a4j:keepAlive` instead of `t:saveState`. @Topicstarter: you need to bind the whole component instead of its value. To set the value use `UIInput#setValue()` and to get it use `UIInput#getValue()`.
BalusC
On the Second page, I am using hidden field as:<code><h:inputHidden id="hidden1" binding="#{backBean.testBoo}"><code>and the getters and setters are as:<code>public UIInput getTestBoo() { return testBoo; } public void setTestBoo(UIInput testBoo) { this.testBoo = testBoo; }<code>On the First I am setting the value as:<code>UIInput test = new UIInput();test.setRendered(true);backBean.setTestBoo(test);<code>But I didnt get no success.I dont no where I went wrong.
I edited my answer with an example.
BalusC
Caused by: java.lang.ClassCastException: java.lang.String incompatible with java.lang.BooleanI get this error doing following:In ClassA i am setting the value as:pc_classB.setBoolean1(true);In classB ,I am doing as your edited code with additional getters and setters for hidden1.And in JSP I am setting render as:<h:panelGroup styleClass="panelGroup" id="panel1" rendered="#{pc_classB.boolean1}">Isn't this is the way ou told me to do.I am getting the above exception.
Add `converter="javax.faces.Boolean"` to the hidden field or use `Boolean.valueOf()` and `String.valueOf()` instead.
BalusC
Still getting : Cannot convert javax.faces.component.html.HtmlInputHidden@154d154d of type class javax.faces.component.html.HtmlInputHidden to class java.lang.Booleanwhen using converter as:<h:inputHidden id="testBoo1" binding="#{pc_classB.hidden1}"><f:converter converterId="javax.faces.Boolean"/></h:inputHidden>
You have apparently declared `hidden1` as `Boolean` instead of `HtmlInputHidden`.
BalusC
I am using:private HtmlInputHidden hidden1 = new HtmlInputHidden(); public HtmlInputHidden getHidden1() { return hidden1; } public void setHidden1(HtmlInputHidden hidden1) { this.hidden1 = hidden1; } public void setBoolean1(boolean boolean1) { hidden1.setValue(boolean1); } public boolean getBoolean1() { return (Boolean) hidden1.getValue();}And in the JSP:<h:inputHidden id="testBoo1" binding="#{pc_classB.hidden1}"> <f:converter converterId="javax.faces.Boolean"/> </h:inputHidden>
Your problem lies somewhere else. I created an SSCCE and I can't reproduce this. I'll add the SSCCE soon.
BalusC
thanks, I am waiting....
This was already done.
BalusC
I tried the way you told me but I still getting that Error 500: javax.servlet.ServletException: Cannot convert javax.faces.component.html.HtmlInputHidden@47f447f4 of type class javax.faces.component.html.HtmlInputHidden to class java.lang.Boolean .I am not understanding why??? The code is exact like the above you pasted but still no success with that exception.
Either there's a bug in your JSF implementation -upgrade it, or there's a bug in your own code. It at least sounds like as if you've set its value with a `HtmlInputHidden` instance instead of a `Boolean` instance.
BalusC
Hi BalucIs this the same probelm too? How do I resolve it.I have a update form, with composite keys All composite keys are displayed in outputbox as I have hidden field for each composite keys.Again these outputbox values are empty after validation error. How do I resolve this. I am on the same page so doesn't it has to have the values. Its making me confused.