Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Struts indexed html:Select tags not working

Posted on 2004-10-23
5
Medium Priority
?
1,678 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
Comment
Question by:PalmDrac
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
5 Comments
 
LVL 2

Expert Comment

by:siliconeagle
ID: 12399786
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
ID: 12421962
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
ID: 12431603
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:
ee_ai_construct earned 0 total points
ID: 12464545
Question answered by asker or dialog valuable.
Closed, 250 points refunded.
ee_ai_construct (replacement part #xm34)
Community Support Admin
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
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 receive an overview of the basics of CSS showing inline styles. In the head tags set up your style tags: (CODE) Reference the nav tag and set your properties.: (CODE) Set the reference for the UL element and styles for it to ensu…
Learn how to create flexible layouts using relative units in CSS.  New relative units added in CSS3 include vw(viewports width), vh(viewports height), vmin(minimum of viewports height and width), and vmax (maximum of viewports height and width).
Suggested Courses

636 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