7 Replies Latest reply on Apr 14, 2008 7:08 PM by kenclark

    Using dataTable to edit values in a list

    kenclark

      I am trying to get this working, it seems simple enough, but I can't seem to make it work.


      I have an object (an entity bean actually) that has a List of child objects (also entity beans, @OneToMany).


      I have a facelet screen that allows editing of the attributes of the bean using standard h:inputText, etc.  That works fine.


      To allow editing of the list of child objects, I have a h:dataTable that contains as a column an h:inputText for the child value attribute I want to edit.


      The problem is I expect to see a list of children objects as filled in from the user form once the action method is called (in a StatefulSessionBean, using Seam conversation).  But the child List is always empty.


      Am I doing this wrong?  Will standard JSF not handle this?


      Thanks for any advice.


      ken clark

        • 1. Re: Using dataTable to edit values in a list
          dhinojosa

          Do you have some code (Entity, Stateful Session Bean, and Page)?

          • 2. Re: Using dataTable to edit values in a list
            kenclark

            Here is everything...


            Child entity, Parent entity, SFSB, and facelet page


            @Entity
            //@Name("customDataValidValue")
            @Table(name = "custom_data_valid_value")
            public class CustomDataValidValue
            {
            
                @SequenceGenerator(name = "customDataValueSeq", sequenceName = "custom_data_value_seq")
                @Id
                @GeneratedValue(generator = "customDataValueSeq")
                @Column(name = "custom_data_value_id")
                private Long customDataValueId;
                @Column(name = "custom_data_value_position")
                private Long customDataValuePosition;
                @Column(name = "custom_data_value_desc")
                private String customDataValueDesc;
                @ManyToOne
                @JoinColumn(name = "custom_data_key")
                private CustomDataConfiguration customDataConfiguration;
            
            //...
            }




            @Entity
            @Name("customDataConfiguration")
            //@Scope(ScopeType.SESSION)
            @Table(name = "custom_data_configuration")
            public class CustomDataConfiguration implements Serializable
            {
            
                @Id
                @Column(name = "custom_data_key")
                private String customDataKey;
                @Column(name = "required_flag")
                private String requiredFlag;
                @ManyToOne
                @JoinColumn(name = "custom_data_type_code")
                private CustomDataType customDataType;
                @Column(name = "custom_data_desc")
                @Length(max = 2000)
                private String customDataDesc;
                @Column(name = "custom_data_label")
                @NotNull
                @Length(max = 200)
                private String customDataLabel;
                @OneToMany(mappedBy = "customDataConfiguration")
                @OrderBy(value="customDataValuePosition")
                private List<CustomDataValidValue> customDataValidValues = new ArrayList<CustomDataValidValue>();
            // ...
            }
            




            @Stateful
            @Name("customDataAction")
            public class CustomDataAction implements CustomDataActionLocal
            {
            
                @PersistenceContext
                private EntityManager em;
                @Logger
                private Log log;
                @In
                private FacesMessages facesMessages;
                @Out(required = false)
                @In(required = false)
                private CustomDataConfiguration customDataConfiguration;
                @Out(required = false)
                private List<CustomDataType> customDataTypes;
                @Out(required = false)
                private List<CustomDataConfiguration> customDataConfigurations;
            
                @Begin
                @End
                public String listCustomDataConfigurations()
                {
                    loadList();
                    return "list";
                }
            
                @Begin(join = true)
                @End
                public String viewCustomDataConfiguration()
                {
                    String customDataKey = Util.toString(FacesContext.getCurrentInstance().
                                                         getExternalContext().getRequestParameterMap().get("customDataKey"));
                    customDataConfiguration = em.find(CustomDataConfiguration.class, customDataKey);
                    return "viewCustomData";
                }
            
                @Begin(join = true)
                @Factory
                public String createCustomDataConfiguration()
                {
                    customDataConfiguration = new CustomDataConfiguration();
                    customDataConfiguration.setRequired(false);
                    getCustomDataTypes();
                    return "editCustomData";
                }
            
                @Begin
                public String editCustomDataConfiguration()
                {
                    String customDataKey = Util.toString(FacesContext.getCurrentInstance().
                                                         getExternalContext().getRequestParameterMap().get("customDataKey"));
                    if (customDataKey != null)
                        customDataConfiguration = em.find(CustomDataConfiguration.class, customDataKey);
                    getCustomDataTypes();
                    return "editCustomData";
                }
            
                @End
                public String cancel()
                {
                    loadList();
                    return "cancel";
                }
            
                @End
                public String save()
                {
                    // Get rid of any empty valid value entries
                    if (customDataConfiguration != null && customDataConfiguration.getCustomDataValidValues() != null)
                        for (Iterator<CustomDataValidValue> i = customDataConfiguration.getCustomDataValidValues().iterator(); i.hasNext();)
                        {
                            CustomDataValidValue vv = i.next();
                            if (Util.isEmpty(vv.getCustomDataValueDesc()))
                                i.remove();
                        }
                    if (customDataConfiguration.getCustomDataType().getCustomDataTypeCode().equals("select"))
                    {
                        if (Util.isEmpty(customDataConfiguration.getCustomDataValidValues()))
                        {
                            // Need to go back to the user for some values
                            facesMessages.add("Please add one or more valid values");
                            addValidValues();
                            return null;
                        }
                        else
                        {
                            // reposition in case anything has been moved around
                            long iPos = 0;
                            for (CustomDataValidValue vv : customDataConfiguration.getCustomDataValidValues())
                            {
                                vv.setCustomDataValuePosition(iPos++);
                            }
                        }
                    }
                    em.merge(customDataConfiguration);
                    em.flush();
                    loadList();
                    return "success";
                }
            
                public String addValidValues()
                {
                    if (customDataConfiguration.getCustomDataValidValues() == null)
                        customDataConfiguration.setCustomDataValidValues(new ArrayList<CustomDataValidValue>());
                    long iPos = customDataConfiguration.getCustomDataValidValues() == null ? 0 : customDataConfiguration.getCustomDataValidValues().size();
                    for (int i = 0; i < 5; i++)
                    {
                        customDataConfiguration.getCustomDataValidValues().add(new CustomDataValidValue(customDataConfiguration, iPos++));
                    }
                    return null;
                }
            
            // ...
            }
            




            <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                            xmlns:s="http://jboss.com/products/seam/taglib"
                            xmlns:ui="http://java.sun.com/jsf/facelets"
                            xmlns:f="http://java.sun.com/jsf/core"
                            xmlns:h="http://java.sun.com/jsf/html"
                            xmlns:ice="http://www.icesoft.com/icefaces/component"
                            template="../layout/template.xhtml">
                
                <ui:define name="body">
                    
                    <ice:form id="selectBranchForm">
                        
                        <h:messages globalOnly="true" styleClass="message"/>
                        
                        <ice:panelGrid id="homePanelGrid" columns="1" columnClasses="leftMenu,leftMenu">
                            
                            <ice:panelGrid columns="2" columnClasses="rightMenu,leftMenu">
                                <h:outputLabel for="keyid" value="Key Id: " />
                                <h:inputText id="keyid" value="#{customDataConfiguration.customDataKey}"/>
                                <h:outputLabel for="typeSelection" value="User Entry Field Type: " />
                                <h:selectOneMenu id="typeSelection" value="#{customDataConfiguration.customDataType}"
                                                 converter="#{customDataAction.customDataTypeConverter}">
                                    <s:selectItems value="#{customDataTypes}" noSelectionLabel="Select a Data Type"
                                                   var="cdt" label="#{cdt.customDataTypeDesc}" />
                                </h:selectOneMenu>
                                <h:outputLabel for="required" value="Required Entry?: " />
                                <h:selectBooleanCheckbox id="required" value="#{customDataConfiguration.required}" />                    
                                <h:outputLabel for="labelentry" value="Label: " />
                                <h:inputText id="labelentry" value="#{customDataConfiguration.customDataLabel}"/>
                                <h:outputLabel for="desc" value="Description (hint): " />
                                <h:inputTextarea id="desc" rows="4" cols="80" value="#{customDataConfiguration.customDataDesc}"/>
                            </ice:panelGrid>
                            <ice:panelGrid columns="1" rendered="#{customDataConfiguration.customDataType.customDataTypeCode=='select'}">
                                <h:commandButton value="Add More Values Fields" action="#{customDataAction.addValidValues}" 
                                                 styleClass="button" />
                                <h:dataTable value='#{customDataConfiguration.customDataValidValues}' var='vv' border="1"
                                             cellpadding="2" cellspacing="0">
                                    <h:column>
                                        <f:facet name="header">
                                            <h:outputText value="Enter all valid values"/>
                                        </f:facet>
                                        <h:inputText value="#{vv.customDataValueDesc}"/>
                                    </h:column>
                                </h:dataTable>
                            </ice:panelGrid>
                            
                            <ice:panelGrid columns="2" columnClasses="leftMenu,leftMenu">
                                <h:commandButton value="Save" action="#{customDataAction.save}" 
                                                 styleClass="button" />
                                <h:commandButton value="Cancel" action="#{customDataAction.cancel}" 
                                                 styleClass="button" />
                            </ice:panelGrid>
                            
                        </ice:panelGrid>
                        
                    </ice:form>
                    
                </ui:define> 
                </ui:composition>
            



            • 3. Re: Using dataTable to edit values in a list
              dhinojosa

              That looks good, although I don't use ICEFaces so some of the tags a familiar but I don't know them intimately. I was wondering, if you put a log statement in the save() method. What do you get? 


              @End
                  public String save()
                  {
                      log.debug(customDataConfiguration);  //added debug statement
                      log.debug(customDataConfiguration.getCustomDataValidValues);  //added debug statement
                      // Get rid of any empty valid value entries
                      if (customDataConfiguration != null && customDataConfiguration.getCustomDataValidValues() != null)
                          for (Iterator<CustomDataValidValue> i = customDataConfiguration.getCustomDataValidValues().iterator(); i.hasNext();)
                          {
                              CustomDataValidValue vv = i.next();
                              if (Util.isEmpty(vv.getCustomDataValueDesc()))
                                  i.remove();
                          }
                      if (customDataConfiguration.getCustomDataType().getCustomDataTypeCode().equals("select"))
                      {
                          if (Util.isEmpty(customDataConfiguration.getCustomDataValidValues()))
                          {
                              // Need to go back to the user for some values
                              facesMessages.add("Please add one or more valid values");
                              addValidValues();
                              return null;
                          }
                          else
                          {
                              // reposition in case anything has been moved around
                              long iPos = 0;
                              for (CustomDataValidValue vv : customDataConfiguration.getCustomDataValidValues())
                              {
                                  vv.setCustomDataValuePosition(iPos++);
                              }
                          }
                      }
                      em.merge(customDataConfiguration);
                      em.flush();
                      loadList();
                      return "success";
                  }
              

              • 4. Re: Using dataTable to edit values in a list
                kenclark

                I used the debugger and put a breakpoint at the same spot.  At that point the customDataValidValues is always an empty list -- so it is basically not being loaded from the datatable (all the other data is there as you would expect.)


                I actually originally had the list reference as a null but changed that thinking it may fix the problem (obviously it didn't.)


                I also put breakpoints in the default constructors of both entities.  The child never gets called (until the save method adds in the dummy entries.)  The parent gets called once by the SeamELResolver.


                Breakpoints in the getCustomDataValidValues and set... methods do not get hit before the save method is invoked, so its clear that nothing is trying to load the values from the dataTable.


                JSF should be able to load the children entries from inputText tags, right?


                Is the JPA stuff getting in the way somehow?


                Thanks,
                ken

                • 5. Re: Using dataTable to edit values in a list
                  dhinojosa

                  You know...I just didn't see if before.  Your persistence is not extended.;)


                  I bet that'll do it. Let me know.


                  @Stateful
                  @Name("customDataAction")
                  public class CustomDataAction implements CustomDataActionLocal
                  {
                  
                      @PersistenceContext(type = PersistenceContextType.EXTENDED)  //Need to be extended in stateful beans
                      private EntityManager em;
                      @Logger
                      private Log log;
                      @In
                      private FacesMessages facesMessages;
                      @Out(required = false)
                      @In(required = false)
                      private CustomDataConfiguration customDataConfiguration;
                      @Out(required = false)
                      private List<CustomDataType> customDataTypes;
                      @Out(required = false)
                      private List<CustomDataConfiguration> customDataConfigurations;
                  
                  
                  

                  • 6. Re: Using dataTable to edit values in a list
                    kenclark

                    No, that didn't change anything.


                    One thing that seems unusual to me:  When the CustomDataConfiguration object is loaded, I see SQL in the JBoss log for reading from the custom-data-configuration table (joined to custom-data-type) -- all good.  But I don't see a select from custom-data-valid-value, which I would expect is needed in order to load the child list.


                    Maybe that is unrelated but since it is the same attribute I wonder if something is going on there.


                    Thanks,
                    ken

                    • 7. Re: Using dataTable to edit values in a list
                      kenclark

                      Can anyone confirm at least that I should be able to do this?


                      Thanks,
                      ken