You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Great Coder <co...@gmail.com> on 2006/10/31 07:53:57 UTC

Data Table Question

I have been trying to get a really simple example to work with myfaces but
had zero success till now. I am hoping someone who understands jsf better
than me (which is probably most of you :-)) could shed some insight into
this.  Sorry for the long post, but I thought it is better to give all the
details in order to explain myself.

Here is what I am trying to do. Basically I am staring out with a simple
screen that presents the user with four empty rows to enter the Box's
(product) height and width. The user can choose to add more rows by clicking
on the Add more button. Once the user is done filling all the product he
needs (user can fill as many rows as he wants), he will submit. But I am
stuck for more than 5 hours on trying to get Add more button to work.  In
short, what I don't understand is how is the form getting populated.
Initially when the screen is displayed, I am creating four empty beans( see
code below) so that I can get corresponding four empty rows initially in the
data table tag (is this a good way to display empty rows, given that
whatever data user puts in needs to go back into my product bean).

Additionally, I am expecting that when I hit on an action button "Add More",
the four beans data (if the user has already filled in some row data) will
be set on my backing bean. Further, I can just attach the extra bean as
needed in my addMore method to the existing set, this way I won't loose the
user entered data. (Again see code below it will be much clearer). But for
some reason, the addMore is not called at all. I have the product display
bean stored in the session
<managed-bean>
    <managed-bean-name>productDisplayBean</managed-bean-name>
    <managed-bean-class>com.riceint.ProductDisplayBean
    </managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>

What I don't understand is if I remove the part where I am creating the four
empty beans in the getProductDataModel method(See code below), then
addMore does
get called when the "Add More" button is clicked (else it is not). So it
seems that initializing the productDataModel is messing up some kind of JSF
states. I do see that when the form is submitted via clicking "Add More" ,
the getProductDataModel/followed by setProductDataModel is called.  This
does not jibe with the way I expected it to work. I would have expected that
all the product beans would be populated based on the user chocies,  and
those beans will be put into the productDataModel since I am iterating over
productDataModel in the t:dataTableTag. Finally JSF would have populated my
productDataBean variable before the "addMore" method was called.  But none
of those is happening; even the setProductDataModel is setting an empty data
model. Strange. I guess I am fundamentally confused in terms of how the data
model data is applied back to the backing beans. Isn't it every row data is
updated in the backing bean?

Anyway here is the code below

Here is a snippet of my JSP

<%@ page session="false" contentType="text/html;charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://myfaces.apache.org/tomahawk" prefix="t"%>
<f:view>
    <h:form id="product_display">
<t:dataTable id="data" styleClass="standardTable"
            headerClass="standardTable_Header"
footerClass="standardTable_Header"
            rowClasses="standardTable_Row1,standardTable_Row2"
            columnClasses="standardTable_Column" var="pData"
            value="#{productDisplayBean.productDataModel}"
            preserveDataModel="false">
            <h:column >
                <f:facet name="header">
                    <h:outputText value="Width" />
                </f:facet>
                <h:inputText id="width" value="#{pData.width}" size="3" >
                   <f:validateLongRange minimum="1" maximum="500" />
                </h:inputText>
            </h:column>
            <h:column>
                <f:facet name="header">
                    <h:outputText value="Height" />
                </f:facet>
                <h:inputText id="height" value="#{pData.height}"  size="3">
                   <f:validateLongRange minimum="1" maximum="500" />
                </h:inputText>
            </h:column>
             <!-- have some more columns here -->
      </t:dataTable>
        <BR/> <BR/>
        <h:commandButton value="Add More" action="#{
productDisplayBean.addMore}"/>

        <h:commandButton value="Submit"
action="some_String_that_is_not_implemented"/>
    </h:form>
    <jsp:include page="inc/mbean_source.jsp" />
</f:view>

Now given this JSP, I have a backing bean that looks like this.
public class ProductDisplayBean {
    private DataModel productDataModel;

    public void addMoreProductBeans(int howMany) {
        //Instantiate the EMPTY BEANs
        ProductBean[] beans = new ProductBean[howMany];
        for (int i = 0; i < beans.length; i++) {
            beans[i] = new ProductBean();
        }

        //Attach it to the data model
        if(productDataModel == null || productDataModel.getWrappedData() ==
null) {
            productDataModel = new ListDataModel(new ArrayList(Arrays.asList
(beans)));
        }  else {
            ((List)productDataModel.getWrappedData()).addAll(new ArrayList(
Arrays.asList(beans)));
        }
    }

    public DataModel getProductDataModel() {

        if(productDataModel == null) {    //This is done in order to start
with 4 empty rows when the screen is displayed for the first time

           //if we don't do this adding beans here, the addMore function is
called properly when the user clicks on the button. But adding this line
           //is confusing JSF
            addMoreProductBeans(4);
        }
        return productDataModel;
    }

    public void setProductDataModel(DataModel productDataModel) {
        this.productDataModel = productDataModel;
    }

    public String addMore() {
        addMoreProductBeans(2);
        return null; //forward it to the same page
    }

}

The ProductBean class is simply a java bean with 2 setters and getters, and
is a serializable class.

Any help would be greatly appreciated.

Thanks

Re: Data Table Question

Posted by Andrew Robinson <an...@gmail.com>.
Your data model should always be null. You are using a request scope
bean, with preserve model = false. Nothing is keeping your model in
memory. I would suggest:

1) make your bean session or conversation scoped
2) use binding so that the control is kept across requests
3) use preserveModel="true"
4) use t:saveState to save the model

Try that out and let us know what difference that makes.

On 10/30/06, Great Coder <co...@gmail.com> wrote:
> I have been trying to get a really simple example to work with myfaces but
> had zero success till now. I am hoping someone who understands jsf better
> than me (which is probably most of you :-)) could shed some insight into
> this.  Sorry for the long post, but I thought it is better to give all the
> details in order to explain myself.
>
> Here is what I am trying to do. Basically I am staring out with a simple
> screen that presents the user with four empty rows to enter the Box's
> (product) height and width. The user can choose to add more rows by clicking
> on the Add more button. Once the user is done filling all the product he
> needs (user can fill as many rows as he wants), he will submit. But I am
> stuck for more than 5 hours on trying to get Add more button to work.  In
> short, what I don't understand is how is the form getting populated.
> Initially when the screen is displayed, I am creating four empty beans( see
> code below) so that I can get corresponding four empty rows initially in the
> data table tag (is this a good way to display empty rows, given that
> whatever data user puts in needs to go back into my product bean).
>
> Additionally, I am expecting that when I hit on an action button "Add More",
> the four beans data (if the user has already filled in some row data) will
> be set on my backing bean. Further, I can just attach the extra bean as
> needed in my addMore method to the existing set, this way I won't loose the
> user entered data. (Again see code below it will be much clearer). But for
> some reason, the addMore is not called at all. I have the product display
> bean stored in the session
> <managed-bean>
>
> <managed-bean-name>productDisplayBean</managed-bean-name>
>     <managed-bean-class>com.riceint.ProductDisplayBean
>     </managed-bean-class>
>     <managed-bean-scope>request</managed-bean-scope>
>   </managed-bean>
>
> What I don't understand is if I remove the part where I am creating the four
> empty beans in the getProductDataModel method(See code below), then addMore
> does get called when the "Add More" button is clicked (else it is not). So
> it seems that initializing the productDataModel is messing up some kind of
> JSF states. I do see that when the form is submitted via clicking "Add More"
> , the getProductDataModel/followed by setProductDataModel is called.  This
> does not jibe with the way I expected it to work. I would have expected that
> all the product beans would be populated based on the user chocies,  and
> those beans will be put into the productDataModel since I am iterating over
> productDataModel in the t:dataTableTag. Finally JSF would have populated my
> productDataBean variable before the "addMore" method was called.  But none
> of those is happening; even the setProductDataModel is setting an empty data
> model. Strange. I guess I am fundamentally confused in terms of how the data
> model data is applied back to the backing beans. Isn't it every row data is
> updated in the backing bean?
>
> Anyway here is the code below
>
> Here is a snippet of my JSP
>
> <%@ page session="false"
> contentType="text/html;charset=utf-8"%>
> <%@ taglib uri=" http://java.sun.com/jsf/html" prefix="h"%>
> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
> <%@ taglib uri=" http://myfaces.apache.org/tomahawk"
> prefix="t"%>
> <f:view>
>     <h:form id="product_display">
> <t:dataTable id="data" styleClass="standardTable"
>             headerClass="standardTable_Header"
> footerClass="standardTable_Header"
>
> rowClasses="standardTable_Row1,standardTable_Row2"
>             columnClasses="standardTable_Column"
> var="pData"
>             value="#{productDisplayBean.productDataModel}"
>             preserveDataModel="false">
>             <h:column >
>                 <f:facet name="header">
>                      <h:outputText value="Width" />
>                 </f:facet>
>                 <h:inputText id="width" value="#{pData.width}" size="3" >
>                    <f:validateLongRange minimum="1" maximum="500" />
>                 </h:inputText>
>             </h:column>
>             <h:column>
>                 <f:facet name="header">
>                     <h:outputText value="Height" />
>                 </f:facet>
>                 <h:inputText id="height" value="#{pData.height}"  size="3">
>                    <f:validateLongRange minimum="1" maximum="500" />
>                 </h:inputText>
>             </h:column>
>              <!-- have some more columns here -->
>       </t:dataTable>
>         <BR/> <BR/>
>         <h:commandButton value="Add More" action="#{
> productDisplayBean.addMore}"/>
>
>         <h:commandButton value="Submit"
> action="some_String_that_is_not_implemented"/>
>     </h:form>
>     <jsp:include page="inc/mbean_source.jsp" />
> </f:view>
>
> Now given this JSP, I have a backing bean that looks like this.
> public class ProductDisplayBean {
>     private DataModel productDataModel;
>
>      public void addMoreProductBeans(int howMany) {
>         //Instantiate the EMPTY BEANs
>         ProductBean[] beans = new ProductBean[howMany];
>         for (int i = 0; i < beans.length; i++) {
>             beans[i] = new ProductBean();
>         }
>
>         //Attach it to the data model
>         if(productDataModel == null || productDataModel.getWrappedData() ==
> null) {
>             productDataModel = new ListDataModel(new ArrayList(Arrays.asList
> (beans)));
>         }  else {
>
> ((List)productDataModel.getWrappedData()).addAll(new
> ArrayList(Arrays.asList(beans)));
>         }
>     }
>
>     public DataModel getProductDataModel() {
>
>         if(productDataModel == null) {    //This is done in order to start
> with 4 empty rows when the screen is displayed for the first time
>
>            //if we don't do this adding beans here, the addMore function is
> called properly when the user clicks on the button. But adding this line
>            //is confusing JSF
>             addMoreProductBeans(4);
>          }
>         return productDataModel;
>     }
>
>     public void setProductDataModel(DataModel productDataModel) {
>         this.productDataModel = productDataModel;
>     }
>
>     public String addMore() {
>         addMoreProductBeans(2);
>         return null; //forward it to the same page
>     }
>
> }
>
> The ProductBean class is simply a java bean with 2 setters and getters, and
> is a serializable class.
>
>  Any help would be greatly appreciated.
>
> Thanks
>
>