8 Replies Latest reply on Apr 21, 2009 3:02 AM by aalves

    Dynamic components

    aalves

      Hello,
      I am a newbie on Jboss seam, and I have a problem trying to create fields on forms dynamically, I have seen several examples but it does not work.
      I get the following exception when I try to render the page: 


      javax.faces.FacesException: javax.el.ELException: /crearActividad.xhtml @23,64 binding="#{crearActividad.containerComponent}": Error reading 'containerComponent' on type com.tresw.reservas.session.CrearActividad_$$_javassist_1



      My Action class is as follows:



      package com.tresw.reservas.session;
      
      import java.util.LinkedList;
      import java.util.List;
      
      import org.jboss.seam.annotations.Begin;
      import org.jboss.seam.annotations.Factory;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Logger;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.log.Log;
      import org.jboss.seam.international.StatusMessages;
      import org.richfaces.component.html.HtmlComboBox;
      import org.hibernate.validator.Length;
      
      import com.tresw.reservas.entity.Tipocampo;
      
      import javax.faces.component.UIColumn;
      import javax.faces.component.UISelectItems;
      import javax.faces.component.html.HtmlInputText;
      import javax.faces.component.html.HtmlOutputText;
      import javax.faces.component.html.HtmlPanelGrid;
      import javax.faces.model.SelectItem;
      
      @Name("crearActividad")
      public class CrearActividad
      {
          @Logger private Log log;
      
          @In StatusMessages statusMessages;
      
          private String value;
          
          @In(required = false, create = true)
          @Out
          private HtmlPanelGrid containerComponent;
      
          public void crearActividad()
          {
              // implement your business logic here
              log.info("crearActividad.crearActividad() action called with: #{crearActividad.value}");
              statusMessages.add("crearActividad #{crearActividad.value}");
          }
      
          public HtmlPanelGrid getContainerComponent() {
                      return containerComponent;
              }
      
              public void setContainerComponent(HtmlPanelGrid containerComponent) {
                      this.containerComponent = containerComponent;
              }
      
              @Length(max = 10)
          public String getValue()
          {
              return value;
          }
        
          public void setValue(String value)
          {
              this.value = value;
          }
          
          public List<SelectItem> getSelectItem()
          {
              List<Tipocampo> campos = new TipocampoList().getResultList();
              List<SelectItem> result = new LinkedList<SelectItem>();
              for(Tipocampo campo : campos)
              {
                      SelectItem item = new SelectItem(campo.getId().intValue(),campo.getTipo());
                      result.add(item);
              }
              return result;  
          }           
          
          public List<Tipocampo> getItems()
          {
              List<Tipocampo> campos = new TipocampoList().getResultList();
              return campos;  
          }           
          
          public void addComponents() {
              //clean previous component
              containerComponent.getChildren().clear();
              
              int nodes = Integer.parseInt(value);
              //dynamically add Child Components to Container Component
              for (int i=0;i<nodes; i++) 
              {
                  UIColumn col = new UIColumn();
                  HtmlOutputText ot = new HtmlOutputText();
                  ot.setValue("Nombre del campo" + ": ");
                  col.getChildren().add(ot);
                  HtmlInputText it = new HtmlInputText();
                  it.setValue("");
                  it.setId("nombre"+i);
                  col.getChildren().add(it);
      
                  UIColumn col2 = new UIColumn();
                  HtmlOutputText ot2 = new HtmlOutputText();
                  ot2.setValue("Tipo del campo" + ": ");
                  col2.getChildren().add(ot2);
                  HtmlComboBox combo = new  HtmlComboBox();
                  UISelectItems items = new UISelectItems();
                  items.setValue(items);
                  combo.getChildren().add(items);
                  col2.getChildren().add(combo);
      
                  
                  if (containerComponent == null) {
                      containerComponent = new HtmlPanelGrid();
                  }
                  containerComponent.getChildren().add(col);
                  containerComponent.getChildren().add(col2);
              }
      
          }
         
          @Factory("containerComponent")
              @Begin(join = true)
              public void start()
          {
                      containerComponent = new HtmlPanelGrid();
              }
      }
      


      And my page is as follows:



      <!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:form id="crearActividadForm">
      
              <rich:panel>
                  <f:facet name="header">crearActividad</f:facet>
                                       <s:decorate id="valueField" template="layout/edit.xhtml">
                              <ui:define name="label">Value</ui:define>
                              <h:inputText id="value" required="true" value="#{crearActividad.value}"/>
                          </s:decorate>
                 
                              <h:panelGrid binding="#{crearActividad.containerComponent}">              
                               <h:commandButton value="Anadir campos" action="#{crearActividad.addComponents}" partialSubmit="true"/>
                              </h:panelGrid>
                 
                  
                      <div style="clear:both"/>          
             
      
              </rich:panel>
      
              <div class="actionButtons">
                  <h:commandButton id="crearActividad" value="crearActividad"
                          action="#{crearActividad.crearActividad}"/>
              </div>
      
          </h:form>
      
      </ui:define>
      
      </ui:composition>
      
      
      



      Can anybody help me?


      Or give me an example on how generating the form dynamically?


      thanks in advance

        • 1. Re: Dynamic components
          thokuest

          There should be a stacktrace showing the reason why the error occures (check your server logs).




          example on how generating the form dynamically?


          See: Richfaces dynamic forms sample

          • 2. Re: Dynamic components
            aalves

            Hi thanks for your reply, but I have the followind problem.
            The user can decide how many fields th form is going to have. The thing is that I have multiple fields pointing to the same bean property. For example:


            How many fields do you want for the new activity? 3


            Since the user choose three, this would appear.


            Field name:This will be and input text  field type: this will be a set of options (selectonemenu)
            Field name:This will be and input text  field type: this will be a set of options (selectonemenu)
            Field name:This will be and input text  field type: this will be a set of options (selectonemenu)


            How do I have to do the binding?
            regards.

            • 3. Re: Dynamic components
              ztiringer

              Try using ui repeat tags



              <ui:repeat value="#{myBean.elements}" var="element">



              • 4. Re: Dynamic components
                aalves

                Hi,
                Thanks for your replies, I have tried ui:repeat.
                This is the scenario, one form in which you enter some that sends me to the dynamic form. In this form I send the number of fields the dynamic form will have. When I enter the dynamic´s form I initialize the list binded to the ui:repeat to the number of fields, but when I fill in the values and send the form that the list cames as a null. This is my code.


                the xhtml


                <!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:form id="crearPasoDosForm">
                
                        <rich:panel>
                            <f:facet name="header">crearPasoDos</f:facet>
                
                               <ui:repeat value="#{crearPasoDos.tiposCamposSeleccionados}" var="campo">
                                 <s:decorate template="layout/edit.xhtml">
                                     <ui:define name="label">Value</ui:define>
                                     <h:inputText id="value" required="true" value="#{campo.nombre}"/>
                                 </s:decorate>
                     
                                    <s:decorate template="layout/edit.xhtml">
                                         <ui:define name="label">Tipo de Campo</ui:define>
                                         <h:selectOneMenu value="#{campo.tipo}" required="true" >
                                              <s:selectItems value="#{crearPasoDos.tiposCampos}" var="tipocampo" label="#{tipocampo.tipo}"/>
                                             <s:convertEntity/>
                                         </h:selectOneMenu>
                                    </s:decorate>          
                               </ui:repeat>
                            <div style="clear:both"/>
                
                        </rich:panel>
                
                        <div class="actionButtons">
                            <h:commandButton id="crearPasoDos" value="crearPasoDos"
                                    action="#{crearPasoDos.crearPasoDos}"/>
                        </div>
                
                    </h:form>
                
                </ui:define>
                
                </ui:composition>




                and the java class


                package com.tresw.reservas.session;


                import java.util.ArrayList;
                import java.util.LinkedList;
                import java.util.List;


                import javax.faces.context.FacesContext;
                import javax.faces.model.SelectItem;


                import org.jboss.seam.annotations.Begin;
                import org.jboss.seam.annotations.Name;
                import org.jboss.seam.annotations.In;
                import org.jboss.seam.annotations.Logger;
                import org.jboss.seam.annotations.web.RequestParameter;
                import org.jboss.seam.contexts.Contexts;
                import org.jboss.seam.log.Log;
                import org.jboss.seam.international.StatusMessages;
                import org.hibernate.validator.Length;


                import com.arjuna.ats.internal.jdbc.drivers.modifiers.list;
                import com.tresw.reservas.bean.Campo;
                import com.tresw.reservas.entity.Tipocampo;
                import com.tresw.reservas.entity.Usuario;


                @Name("crearPasoDos")
                public class CrearPasoDos
                {
                    @Logger private Log log;
                
                    @In StatusMessages statusMessages;
                
                    private Integer cantidad;
                    
                    private List<Campo> tiposCampoSeleccionados;
                
                    private List<Tipocampo> tiposCampos;
                    
                    
                    public void crearPasoDos()
                    {
                        // implement your business logic here
                         log.info("crearPasoDos.crearPasoDos() action called with:");
                        statusMessages.add("crearPasoDos ");
                    }
                
                    public List<Tipocampo>  getTiposCampos()
                    {
                //         List<Tipocampo> campos = new TipocampoList().getResultList();
                //         SelectItem[]  result = new SelectItem[campos.size()];
                //         int i =0;
                //         for(Tipocampo campo : campos)
                //         {
                //              SelectItem item = new SelectItem(campo.getId().intValue(),campo.getTipo());
                //              result[i]=item;
                //              i++;
                //         }
                         return new TipocampoList().getResultList();     
                    }
                
                    
                    public void setTiposCampos(List<Tipocampo>  campos)
                    {
                         this.tiposCampos=campos;
                    }
                    
                    
                    public void setTiposCamposSeleccionados(List<Campo> seleccionados)
                    {
                         this.tiposCampoSeleccionados=seleccionados;
                    }
                    
                    public List<Campo> getTiposCamposSeleccionados()
                    {
                         return this.tiposCampoSeleccionados;
                    }
                    
                    public Integer getCantidad()
                    {
                        return cantidad;
                    }
                  
                    public void setCantidad(Integer cantidad)
                    {
                        this.cantidad = cantidad;
                    }
                  
                    @Begin(join = true)
                    public void start()
                    {
                              //tiposCampoSeleccionados = new ArrayList<String>();
                              statusMessages.add("asdas: " + Contexts.getSessionContext().get("cantidad"));
                              cantidad = (Integer)Contexts.getSessionContext().get("cantidad");
                              if(tiposCampoSeleccionados==null)
                              {
                                   tiposCampoSeleccionados=new ArrayList<Campo>();
                                   for(int i = 0; i<cantidad; i++)
                                        tiposCampoSeleccionados.add(new Campo("asdasdasd","Texto largo"));
                              }
                              
                    }
                }




                Any ideas?

                • 5. Re: Dynamic components
                  aalves

                  Can anyone help?

                  • 6. Re: Dynamic components
                    ztiringer

                    Try using crearPasoDos.tiposCamposSeleccionados.nombre instead of campo.nombre etc. as binding in your xhtml

                    • 7. Re: Dynamic components
                      ztiringer

                      Ignore previous reply, that binding should be fine.
                      Where in your code do you check if your list is null? I think in crearPasoDos(), it should work...Do you get any errors in the log?

                      • 8. Re: Dynamic components
                        aalves

                        Hi,
                        Thanks for your replies, I founde the problem now. So it works, I did not put any scope so everytime it created everything reseting the values.
                        Regards