Bonjour,
faisant suite à ce post (où j'ai finalement dû opter pour l'emploi du javascript, faute d'alternative), j'ai quelques soucis avec mon formulaire composé de collections.
Un screenshot:
J'ai une liste d'items (ici composés d'un nom & langue) rangés dans une collection.
Un unique bouton 'add' permet d'ajouter un nouvel item (des MultiLangStringBean); un bouton 'remove' pour chaque item permet de supprimer l'item correspondant.
En premier jet, j'avais implémenté une ActionForm contenant une liste d'items:
La JSP inclut quant à elle des champs 'strutsAction' et 'id'. Ils sont peuplés en javascript lors du clic sur un bouton, et permettent de renseigner quel bouton a été cliqué. La JSP ressemble à ça:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 public class TestForm extends ActionForm { public static class MultiLangStringBean implements Serializable { private String lang = ""; private String name = ""; public get/*...*/ public set/*...*/ } private ArrayList names = new ArrayList(); public ArrayList getNames() { return names; } public void setNames(ArrayList names) {this.names = names;}
Voivi le code de l'Action qui est appelé lors du submit (/edition/testForm) et qui fait le bon traitement en fonction de la 'strutsAction' (notamment pour la strutsAction 'addName'):
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 <script language="JavaScript"> function setAction(action, firstParam, secondParam) { document.forms[0].strutsAction.value = action; document.forms[0].id.value = firstParam; </script> <html:form action="/edition/testForm"> <html:hidden property="strutsAction"/> <html:hidden property="id"/> <html:submit onclick="setAction('addName', '');"> <bean:message key="button.add"/> </html:submit> <nested:iterate property="names" indexId="index"> <html:submit onclick="setAction('removeName', '${index}');"> <bean:message key="button.remove"/> </html:submit> lang: <nested:text property="lang" size="50"/> name: <nested:text property="name" size="50"/> </nested:iterate> <html:submit onclick="setAction('save', '');"> <bean:message key="button.save"/> </html:submit> </html:form>
Enfin, la définition de l'Action mapping dans le struts-config.xml qui boucle sur la même page (/edition/testForm): lorsque le formulaire est validé l'action renvoie à nouveau vers le formulaire (.edition.testForm) pour continuer l'édition
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 public class TestFormSubmitAction extends AbstractApplicationAction { public ActionForward execute(/* ...*/) { TestForm testForm = (TestForm)form; /* ... */ if (testForm.getStrutsAction().equals("addName")) { testForm.getNames().add(new TestForm.MultiLangStringBean()); } }
Problème:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 <action path="/edition/testFormSubmit" type="test.TestFormSubmitAction" name="testForm" input=".edition.testForm" validate="true" scope="request"> <set-property property="cancellable" value="true"/> <forward name="success" path=".edition.testForm" redirect="true"/> </action>
Ce code ne marche que pour un seul ajout. Si je clique deux fois de suite sur le bouton 'add', le deuxième clic me sort une belle exception:
Après moults et moults tests dans tous les sens, il semblerait que le formulaire n'arrive pas à gérer son repeuplement lorsque la collection 'names' a changé de taille (ie. lorsque mon code dans TestFormSubmitAction lui a ajouté un item).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 javax.servlet.ServletException: BeanUtils.populate org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:286) /*...*/ cause mère: javax.servlet.ServletException: BeanUtils.populate org.apache.struts.util.RequestUtils.populate(RequestUtils.java:475) /*...*/ cause mère: java.lang.IndexOutOfBoundsException: Index: 1, Size: 1 java.util.ArrayList.RangeCheck(Unknown Source) java.util.ArrayList.get(Unknown Source) org.apache.commons.beanutils.PropertyUtilsBean.getIndexedProperty(PropertyUtilsBean.java:511)
La seule solution actuelle est pour moi de déporter toutes les collections de mon formulaire de la 'form' vers un bean indépendant que je stocke dans la session (request.getSession().setAttribute(monBean)). Ma classe ActionForm ne contenant alors plus qu'une référence vers ce bean externalisé.
Mais ça ne me paraît vraiment pas propre et ça cause d'autres effets de bord. J'imagine pourtant que ce que j'essaie de faire est loin d'être inhabituel...
Comment puis-je gérer ce souci ?
Merci d'avance![]()
Partager