7 Replies Latest reply on Apr 18, 2011 5:15 PM by fabio.benigni

    Multiple h:forms with a:repeat

    Daniel Wachter Newbie

      Hello fans of Seam!


      I'm trying to have multiple h:forms on a page which are rendered with a a:repeat component.
      If I have only one generated h:form, everything works perfect. If I have multiple h:forms, only the latest h:form will work!
      (If I try to submit another form then the last, only null is passed trough my action!)



      View:

      <a:repeat var="alertGroup" value="#{c_GroupedActiveAlerts}">
      <h:form>
        <div class="right">     
          <h:selectOneMenu id="states" required="false" value="#{alertAction.stateDescriptionID}">
            <s:selectItems value="#{c_StateDescriptions}" var="stateDescription" label="#{db_msg.show(stateDescription.labelKey)}" itemValue="#{stateDescription.ID}" />
          </h:selectOneMenu>
                          
          <img src="img/clear.gif" width="1" height="1" alt="" />     
          <h:commandButton action="#{alertAction.writeStates(alertGroup.key)}" value="#{msg.f_state}" />
          <img src="img/clear.gif" width="1" height="1" alt="" />
        </div>                  
      </h:form>
      </a:repeat>
      



      The action has a property stateDescriptionID which can be called over the getters/setters.


      Is it possible to have several forms, generated trough a list of objects? (e.g. a:repeat, ui:repeat, c:foreach...)

        • 2. Re: Multiple h:forms with a:repeat
          Daniel Wachter Newbie

          unfortunately i doesn't found a solution for my problem.
          perhaps you have another way to solve your problem...


          or you have a solution!?
          ;-)

          • 3. Re: Multiple h:forms with a:repeat
            Rizwan Newbie

            Sorry for the late response, but this post will definitely help someone with a similar issue.
            Problem with multiple forms on a single page is somewhat confusing. It depends on what you intend to do, i.e. what is the end goal.
            I would suppose that you would want to show multiple objects of same class on one page. The user then should be able to manipulate various attributes of each and be able to submit them individually. Following example illustrates just that, but note only ONE h:form element is required:


            <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                                         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
            <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:rich="http://richfaces.org/rich"
                            xmlns:a="http://richfaces.org/a4j"
                            template="layout/template.xhtml">
                                   
            <ui:define name="body">
            
            <h:panelGrid columns="1">
                <h:messages globalOnly="true" styleClass="message"/>
                <!-- This is a comment ans has not been repaired yet -->
                <h:form id="nameForm" >
                    <rich:dataGrid value="#{dataListTest.entList}" var="exentity">
                         
                              <h:panelGrid columns="2">
                                   <h:outputText value="Old name" />
                                   <h:outputText value="#{exentity.name}" />
                                   <h:outputText value="Provide new name" />
                                   <h:inputText value="#{exentity.name}" />
                                   <h:commandButton action="#{dataListTest.saveData(exentity)}" value="Save Name" />
                              </h:panelGrid>
                         
                    </rich:dataGrid>
                </h:form>
               </h:panelGrid>
                
                
            </ui:define>
            
            </ui:composition>
            
            


            The entity class:


            package org.domain.seamtest.entity;
            
            import java.io.Serializable;
            import javax.persistence.Entity;
            import javax.persistence.Id;
            import javax.persistence.GeneratedValue;
            import javax.persistence.Version;
            import org.hibernate.validator.Length;
            import org.jboss.seam.annotations.Name;
            
            @Entity
            @Name("exentity")
            public class ExampleEntity implements Serializable,MarkerInterface {
                 
                 /**
                  * 
                  */
                 private static final long serialVersionUID = 4875063131529610826L;
                 //seam-gen attributes (you should probably edit these)
                 private Long id;
                 private Integer version;
                 private String name;
                 
                //add additional entity attributes
                 
                 //seam-gen attribute getters/setters with annotations (you probably should edit)
                      
                 @Id @GeneratedValue
                 public Long getId() {
                      return id;
                 }
            
                 public void setId(Long id) {
                      this.id = id;
                 }
                 
                 @Version
                 public Integer getVersion() {
                      return version;
                 }
            
                 private void setVersion(Integer version) {
                      this.version = version;
                 }        
                 
                 @Length(max=20)
                 public String getName() {
                      return name;
                 }
            
                 public void setName(String name) {
                      this.name = name;
                 }        
            }
            


            and the bean class


            package org.domain.seamtest.session;
            
            import java.util.ArrayList;
            import java.util.List;
            
            import javax.ejb.Remove;
            import javax.ejb.Stateful;
            
            import org.domain.seamtest.entity.ExampleEntity;
            import org.domain.seamtest.entity.MarkerInterface;
            import org.jboss.seam.annotations.In;
            import org.jboss.seam.annotations.Name;
            import org.jboss.seam.annotations.Begin;
            import org.jboss.seam.annotations.End;
            import org.jboss.seam.annotations.Destroy;
            import org.jboss.seam.annotations.Logger;
            import org.jboss.seam.faces.FacesMessages;
            import org.jboss.seam.log.Log;
            
            @Stateful
            @Name("dataListTest")
            public class DataListTestBean implements DataListTest {
                 @In FacesMessages facesMessages;
                 @Logger private Log log;
                private List<MarkerInterface> entList = new ArrayList<MarkerInterface>();
                private int value;
                 
                private String name;
               
            
                public DataListTestBean(){
                    ExampleEntity e1 = new ExampleEntity();
                    e1.setName("name1");
                    this.entList.add(e1);
                    ExampleEntity e2 = new ExampleEntity();
                    e2.setName("name2");
                    this.entList.add(e2);
                    ExampleEntity e3 = new ExampleEntity();
                    e3.setName("name3");
                    this.entList.add(e3);
               }
               
                 public void saveData(ExampleEntity ex){
                      System.out.println("The old name: "+ex.getName());
                      System.out.println("The new name: "+this.name);
                      System.out.println("The id "+ex.getId());
                      this.facesMessages.add("saved name: "+ex.getName());
                      this.log.info("Now saving...");
                 }
            
                 @Begin
                 public String begin()
                 {
                      //implement your begin conversation business logic
                      log.info("beginning conversation");
                      return "success";
                 }
                 
                 public String increment()
                 {
                      log.info("incrementing");
                      value++;
                      return "success";
                 }
                 
                 //add additional action methods that participate in this conversation
                 
                 @End
                 public String end()
                 {
                    //implement your end conversation business logic
                    log.info("ending conversation");
                      return "home";
                 }
                 
                 public int getValue()
                 {
                      return value;
                 }
                 
                 public List<MarkerInterface> getEntList() {
                      return entList;
                 }
                 
                 @Destroy @Remove                                                                      
                 public void destroy() {}
            
                 public String getName() {
                      return name;
                 }
            
                 public void setName(String name) {
                      this.name = name;
                 }     
            }
            



            Try it out and you will see that when you enter a name in input field and submit form, then only that attribute of current instance is updated.
            The example is somewhat crude, but it does convey the idea. So there is really no need to have multiple h:form-elements in this case.


            Rizwan Qureshi




            • 4. Re: Multiple h:forms with a:repeat
              Philip Murphy Newbie

              How does this work? You don't have any implementation for the save method??? What type of Entity Manager would you use - maybe something like this?



              @PersistenceContext(type = PersistenceContextType.EXTENDED)
              private EntityManager entityManager;
              

              • 5. Re: Multiple h:forms with a:repeat
                John Lennon Newbie

                Hi,


                You might be wrong here :(


                It's true that the method will be called only for one entity - the one which you've passed to:



                <h:commandButton action="#{dataListTest.saveData(exentity)}" value="Save Name" />




                But all entities will be updated to the current state of the screen no matter which Save Name button you press.


                Regards,
                Adam.

                • 6. Re: Multiple h:forms with a:repeat
                  John Lennon Newbie

                  Hi,


                  To solve the problem which I'm mentioning in my post (...But all entities will be updated to the current state of the screen no matter which Save Name button you press. ...) you should add the a4j:region tag.


                  In my approach I'm not using h:.. tags but a4j:... tags so instead of




                  <h:form id="nameForm">





                  I'm using:




                  <a4j:form id="nameForm">





                  and instead of:



                  <h:commandButton...





                  I'm using:



                  <a4j:commandButton...




                  additionally I've added a4j:region tag around each repeated element:




                  <a4j:region>
                  <h:panelGrid columns="2">
                  ...
                  </h:panelGrid>
                  </a4j:region>



                  Regards,
                  Adam.

                  • 7. Re: Multiple h:forms with a:repeat
                    fabio.benigni Newbie

                    Hi all,
                    I have the same problem that has been described before and which does not seem to have been resolved in subsequent discussions.
                    I must be able to enter, within a single page, a form for each element result in a list.
                    I can't use only one form.
                    I have the same Daniel problem, if I have only one generated h:form, everything works perfect. If I have multiple h:forms, only the latest h:form will work! (If I try to submit another form then the last, only null is passed trough my action!)
                    This is a snippet of code:




                    <ui:repeat var="element" value="#{myService.elementList}">
                                    
                                               
                                               
                                    <rich:simpleTogglePanel switchType="client"
                                                            label="#{element.codeElement} - #{element.description}" 
                                                            opened="#{myService.isUiSelected(element)}"
                                                            onexpand="expand#{element.codeElement}()"
                                                            oncollapse="collapse#{element.codeElement}()">
                                        
                                    
                            
                            <h:form id="newKindForm">
                              <a:commandLink ajaxSingle="true" id="idLink" onclick="#{rich:component('newMyPanel')}.show()">
                               <a:commandButton id="myButton" 
                                                value="new Form"
                                             action="#{myService.newForm(element)}"/> 
                               </a:commandLink>                       
                            </h:form>
                                        
                                        
                            <rich:modalPanel id="newMyPanel" autosized="true" width="450">
                               <f:facet name="header">
                                 <h:outputText value="My Pannel Title" />
                               </f:facet>
                               <f:facet name="controls">
                                  <h:panelGroup>
                                     <h:graphicImage value="/img/close.png" 
                                                     id="hidelink"
                                                     styleClass="hidelink" />
                                        <rich:componentControl for="newMyPanel" 
                                                               attachTo="hidelink"
                                                               operation="hide" 
                                                               event="onclick" />
                                  </h:panelGroup>
                               </f:facet>
                               
                             
                        
                        <!-- THIS IS THE PROBLEMATIC FORM -->
                        <h:form>
                             <a:include viewId="../myRepeatableForm.xhtml" />
                        </h:form>
                        
                        
                        
                        </rich:modalPanel>
                        
                        
                        
                        </ui:repeat>
                    






                    Can I use the ui:repeat tag?
                    Instead I have to use the c:foreach tag?
                    Is It a possible realization?
                    I tried hard to find a solution to this problem but I could not find anything that was satisfactory.
                    I hope that someone can help me.
                    Thank you