Solved

Struts indexed html:Select tags not working

Posted on 2004-10-23
1,612 Views
Last Modified: 2013-11-19
Hello Experts!
 
I'm using Struts and I'm trying to create some dynamic html:select dropdown lists. I say dynamic because these "select" controls should be rendered based on an arraylist of objects that is created in an action that setups the form. If this ArrayList contains two objects, then two html:select should be created, if contains three, then three are created and so on...
 
Since I don't know how many objects the ArrayList contains at runtime, I supposed that I needed something dynamic, since I need the selected value of each select list in the action that gets called when the form is submitted (and this property must be specified in the select tag). I checked the Struts docs and found out about the "Indexed" property of the html:select, I also found a doc at this URL: http://struts.apache.org/faqs/indexedprops.html that describes more or less what I need to do, but I tried to do it in the described way and it doesn't works, so I need help with this problem ASAP.
 
The code I'm using in the JSP this:
 

<logic:iterate id="caraciter" name="crearServicioForm" property="caracteristicas" indexId="ctr">
  <td class="cuerpotabla">
  <b><bean:write name="caraciter" property="descripcion"/></b><br><br>
  <html:select name="crearServicioForm" property="codValorSeleccionado" indexed="true">
   <html:optionsCollection name="caraciter" property="valores" value="id" label="descripcion"/>
  </html:select>
  </td>
</logic:iterate>

 
In the formbean "crearServicioForm" I have this:
 

The ArrayList that contains the objects over which we iterate is
private ArrayList caracteristicas = null;
 
The array that I created to store the selected value of each select is:
private String[] codValorSeleccionado = {};
 
      public String getCodValorSeleccionado(int i) {
            return codValorSeleccionado[i];
      }

      public void setCodValorSeleccionado(int i, String value) {
            this.codValorSeleccionado[i] = value;
      }

      public String[] getCodValorSeleccionado() {
            return codValorSeleccionado;
      }

      public void setCodValorSeleccionado(String[] codValorSeleccionado) {
            this.codValorSeleccionado = codValorSeleccionado;
      }

 
In the resulting html the selects are rendered like this:

<select name="crearServicioForm[0].codValorSeleccionado>
<select name="crearServicioForm[1].codValorSeleccionado">

 
(That's when the ArrayList contains two objects)
 
One thing that makes me curious is that the brackets are in the form, shouldn't it read crearServicioForm.codValorSeleccionado[i] ???
 
An interesting fact is that the page gets displayed without errors, thus I suppose that struts is finding a match between the codValorSeleccionado property in the page and the methods in the formbean. But it just doesn't works, no errors in the server console, but doesn't works.
 
I debugged and found out that in the action that gets called when submitting the page, the "getCodValorSeleccionado()" method of the formbean returns an empty array, thus the setCodValor... method that struts invokes is not filling the array.
 
In the document about indexed tags in the jakarta docs they talk about some way to handle "the wrinkle" of using indexed tags, in that you put the name of your member variable in the "name" atribute, but they show it with a html:text tag... I tried to do a similar thing with my select tag and the server reported an error of "codValorSeleccionado bean not found in any scope" which sound logical.
 
I also tried a method they described in which they use the IndexId of the iterate tag, and not the indexed of the html tag. Then they use a scriptlet to render that index in the property attribute. But that way doesnt work... it reports an arrayoutofbound error.
 
If you need any additional info or code let me know... but please give me some light on this.
 
Thanks.
 
PalmDrac
0
Question by:PalmDrac
    4 Comments
     
    LVL 2

    Expert Comment

    by:siliconeagle
    We reading in indexed pages i use the following extension to Vector which creates a bea at a given index if it doesn't exist.
    public class BeanVector extends Vector implements HttpSessionBindingListener{
        /**
           * Comment for <code>serialVersionUID</code>
           */
          private static final long serialVersionUID = 3515707269258088958L;
          private Class beanClass;
        /**
         * Constructor for BeanVector
         * @param initialCapacity
         * @param capacityIncrement
         */
        public BeanVector(int initialCapacity, int capacityIncrement) {
            super(initialCapacity, capacityIncrement);
        }

        /**
         * Constructor for BeanVector.
         * @param initialCapacity
         */

        public BeanVector(int initialCapacity) {
            super(initialCapacity);
        }

        /**
         * Constructor for BeanVector.
         */
        public BeanVector() {
            super();
        }
        /**
         * Constructor for BeanVector.
         * @param c
         */
        public BeanVector(Collection c) {
            super(c);
        }

        public BeanVector(Class c) {
            super();
            this.beanClass = c;
        }

        /**
         * Method getEmptyBeanClass. Creates a bean of the defind class (using the constructor of no parameters) and returns it.
         * @return Object
         */

        private Object getEmptyBeanClass() {
            Class[] classSignature = { };
            Object[] initArgs = {};
            Object o = null;
            try {
                o = this.beanClass.getConstructor(classSignature).newInstance(initArgs);
            } catch (Exception e) {
                //log.debug(this.getClass().toString() + ":" + e.getClass().toString() + ":" + e.getMessage());
            }
            return o;
        }



        /**
         * This get method checks if the defined bean is on the vector,
         * if not the vector is expanded to add the required indexes,
         * if there is no bean at the required index then a bean is created and set at the required index,
         *  the created bena is the passed back as in a normal get operation.
         * @see java.util.List#get(int)
         */

        public Object get(int i) {
            try {
                Object o = super.get(i);
                if (o == null) {
                    super.set(i, getEmptyBeanClass());
                }
            } catch (ArrayIndexOutOfBoundsException ex) {
                while (!(super.size() > i)) {
                    super.add(getEmptyBeanClass());
                }
            }
            return super.get(i);
        }



        public Object remove(int i) {
            Object o = null;
            try {
                o = super.remove(i);
            } catch (ArrayIndexOutOfBoundsException a) {
            }
            return o;
        }

          public void valueBound(HttpSessionBindingEvent arg0) {

          }

          public void valueUnbound(HttpSessionBindingEvent arg0) {
                 for (int i=0;i<size();i++) {
                Object o=get(i);
                if (o instanceof HttpSessionBindingListener) {((HttpSessionBindingListener) o).valueUnbound(arg0);}
                 }
          }
    }

    so if this vector is used in crearServicioForm in place of your ArrayList or String[] (for codValorSeleccionado) so it is initialised like this :-
    private BeanVector caracteristicas = new BeanVector(String.getClass());
    * you also need a getter/setter for the BeanVector;

    but this also works where other beans are stored in the vector as well, not just strings.

    0
     

    Author Comment

    by:PalmDrac
    Well I solved the problem!

    I was able to use the indexed property as I wanted it. This is the solution:

    - I kept the form bean exactly as I showed in the original message, with the "indexed" methods and the common methods.

    - I used the "indexId" attribute of the logic:iterate tag, with this I was able to have in a script variable with the index of the current iteration. I deleted the "indexed" attribute of the html:select tag. Then I used a small scriptlet to add the index to the name attribute of the select tag, that way each of the select tags that are dynamally generated will insert it's selected value into the given position of the codValorSeleccionado array.

    The code of the iteration was changed as follows:

    <logic:iterate id="caraciter" name="crearServicioForm" property="caracteristicas" indexId="ctr">
      <td class="cuerpotabla">
      <b><bean:write name="caraciter" property="descripcion"/></b><br><br>
      <html:select name="crearServicioForm" property="codValorSeleccionado" property='<%="codValorSeleccionado[" + ctr + "]" %>'>
       <html:optionsCollection name="caraciter" property="valores" value="id" label="descripcion"/>
      </html:select>
      </td>
    </logic:iterate>

    Now the real secret is that the codValorSeleccionado array must be intialized with some value in the action that prepares the JSP page, 'cause otherwise the server will throws an "ArrayOutOfBounds" exception. So to fix this I took the array and initialize it in the action with as many "0" as select:tags I was going to render in the page (this number is given by the amount of objects that are contained in the arraylist that generates the select:tags.

    And that's it, it works.

    Definitely the Struts documentation is very poor, 'cause I was not able to make indexed tags work as they described it in the docs.
    0
     
    LVL 2

    Expert Comment

    by:siliconeagle
    yes what you have done should work as well - although index=true works with the modified vector above which is another way of avoiding ArrayIndexOutOfBoundsEx
    0
     

    Accepted Solution

    by:
    Question answered by asker or dialog valuable.
    Closed, 250 points refunded.
    ee_ai_construct (replacement part #xm34)
    Community Support Admin
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

    Course: JavaScript Coding - Massive 12-Part Bundle

    Regardless of your programming skill level, you'll go from basics to advanced concepts in a vast array of JavaScript subjects including Sammy.js, Agility.js, Ember.js, Node.js, jQuery, AJAX, Extjs, AngularJS, Knockout.js, and JSON.

    Suggested Solutions

    I found this questions asking how to do this in many different forums, so I will describe here how to implement a solution using PHP and AJAX. The logical flow for the problem should be: Write an event handler for the first drop down box to get …
    JavaScript has plenty of pieces of code people often just copy/paste from somewhere but never quite fully understand. Self-Executing functions are just one good example that I'll try to demystify here.
    The viewer will learn how to dynamically set the form action using jQuery.
    The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

    884 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    19 Experts available now in Live!

    Get 1:1 Help Now