IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Wicket Java Discussion :

Inserer un DropdownChoice dans un ListView


Sujet :

Wicket Java

  1. #1
    Membre à l'essai
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Points : 10
    Points
    10
    Par défaut Inserer un DropdownChoice dans un ListView
    Bonsoir,

    Je suis débutant sur wicket et je cale sur un problème.

    J'utilise un ListView pour alimenter une table HTML. Pour chaque ligne de cette table j'ai un pauvre label et une DropDownChoice.

    J'arrive à afficher ma table. Mais lorsque je veux soumettre le formulaire, je ne recupere pas les changements sur la DropDownChoice.

    J'imagine que je m'emmele les pinceaux quand à l'utilisation d'un modèle. J'ai lié à mon formulaire un CompoundPropertyModel, et je pense que le problème vient du fait que mon ListView n'est pas bien cablé sur ce CompoundPropertyModel.

    Voici le code, je mets tout le markup et tout le java. En gras la partie qui pose problème !

    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    <wicket:extend>
    	<form wicket:id="form">	
    	<div class="bordure" style="padding:5px; height:15%">
    		<div class="titreSection">
    			Template Page &nbsp;
    			<img src="images/button_preview32.png" title="Pr&eacute;visualisation" onClick="(alert('previ'))"/>
    			<img src="images/button_arbo32.png" title="Arborescence" onClick="(alert('arborescence'))"/>
    			<button wicket:id="valider" type="submit"><img src="images/button_valider32.png" title="Valider"/></button>
    			<img align="right" src="images/button_annuler32.png" title="Annuler" onClick="getAjaxResponse('templatePageConsultation.html');"/>
    			<img align="right" src="images/button_delete32.png" title="Supprimer" onClick="supprimerTemplatePage();"/>
    		</div>
    		<br>
    		<div style="padding:5px">
    			<span style="width:50px;">Identifiant :</span>
    			<span wicket:id="templatePageBean.idTemplatePage" style="font-weight:bold">idTemplatePage</span>
    			<br/>
    			<br/>
    			<span style="width:50px;">Nom :</span>
    			<input wicket:id="templatePageBean.nom" type="text" id="nom" value="nom"></input>
    		</div>
    	</div>	
    	<br>
    	
    	<div class="bordure" style="padding:5px">
    		<p class="titreSection"><b>Zones</b></p>
    		<div style="padding:5px">
    			<select wicket:id="listeZones">
    				<option value="-1">--S&eacute;lectionner une zone--</option>
    			</select>
    			<input type="button" name="ajouterZone" value="Ajouter" onClick="javascript:ajouterZone();" />
    		</div>
    		<table id="tableZones" width="40%">
    		  <thead>
    			<tr>
    			  <th width="10px"></th>				
    			  <th width="60%" align="left">Nom</th>
    			  <th width="30%">Position</th>
    			</tr>
    		  </thead>	
    			<tr wicket:id="templatePageBean.positionsZones" class="two">
    				<td></td>
    				<td><span wicket:id="zoneBean.nom"></span></td>
    				<td><select wicket:id="alignement"></select></td>
    			</tr>  
    		</table>
    		
    		<div style="float:clear-both;padding:5px">	
    			<input type="button" name="supprimerZone" value="Supprimer"" />
    			<input type="button" name="up" value="Up"/>
    			<input type="button" name="down" value="Down"" />
    		</div>
    	
    	</div>
    	</form>	
    	</wicket:extend>
    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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    public ViewOrUpdateTemplatePage() {
    		
    		final List<String> listeAlignement = new ArrayList<String>(); 
    		listeAlignement.add(ConstantesPresentation.FLOAT_LEFT);
    		listeAlignement.add(ConstantesPresentation.FLOAT_RIGHT);
    		listeAlignement.add(ConstantesPresentation.CLEAR_BOTH);
    		
    		CompoundPropertyModel pageModel = new CompoundPropertyModel(
    				new LoadableDetachableModel() {
    					private static final long serialVersionUID = 1L;
    					
    					ViewOrUpdateTemplatePageBean beanPage = new ViewOrUpdateTemplatePageBean();
    					
    					@Override
    					protected Object load() {
    						TemplatePageBean templatePageBean = manageTemplatePage.findTemplatePageById(1);
    						beanPage.setTemplatePageBean(templatePageBean);
    						
    						List<ZoneBean> listeZonesBean = manageZone.findAllZones();
    						beanPage.setListeZones(listeZonesBean);
    						
    						beanPage.getListeAlignement().add(ConstantesPresentation.FLOAT_LEFT);
    						beanPage.getListeAlignement().add(ConstantesPresentation.FLOAT_RIGHT);
    						beanPage.getListeAlignement().add(ConstantesPresentation.CLEAR_BOTH);
    						
    						log.debug("Load TemplatePageBean : " + templatePageBean.toString());
    						log.debug("Liste zone bean size : " + listeZonesBean.size());
    						return beanPage;
    					}
    				});
    		
    		Form form = new Form("form", pageModel) {
    			private static final long serialVersionUID = 1L;
    
    			@Override
    			protected void onSubmit() {
    				TemplatePageBean t = ((ViewOrUpdateTemplatePageBean)getModelObject()).getTemplatePageBean();
    				List<PositionZoneBean> listePositionZoneBean = ((ViewOrUpdateTemplatePageBean)getModelObject()).getTemplatePageBean().getPositionsZones();
    				for (PositionZoneBean posBean : listePositionZoneBean) {
    					log.debug(posBean.toString());
    				}
    				t.setPositionsZones(listePositionZoneBean);
    				log.debug("Submit TemplatePageBean : " + t.toString());
    				manageTemplatePage.modifyTemplatePage(t);
    			}
    		};
    			
    		// TODO : mapper idZone dans le renderer
    		ChoiceRenderer listeZonesRenderer = new ChoiceRenderer<ZoneBean>("nom");
    		DropDownChoice ddZones = new DropDownChoice("listeZones", ((ViewOrUpdateTemplatePageBean)pageModel.getObject()).getListeZones(), listeZonesRenderer);
    		form.add(ddZones);
    		
    		form.add(new Button("valider"));
    		
    		Label labelId = new Label("templatePageBean.idTemplatePage");
    		form.add(labelId);
    		form.add(new TextField<String>("templatePageBean.nom"));
    		
    		ListView positionZoneListView = new ListView<PositionZoneBean>("templatePageBean.positionsZones", ((ViewOrUpdateTemplatePageBean)pageModel.getObject()).getTemplatePageBean().getPositionsZones()) {
    			
    			private static final long serialVersionUID = 1L;
    
    			@Override
    			protected void populateItem(ListItem<PositionZoneBean> item) {
    				
    				item.setModel(new CompoundPropertyModel(item.getModel()));
    
    				String idMarkupNom = "zoneBean.nom";
    				log.debug("idMarkupNom " + idMarkupNom);
    				item.add(new Label(idMarkupNom));
    				
    				String idMarkupAlignement = "alignement";
    				log.debug("idMarkupNom " + idMarkupAlignement);
    				item.add(new DropDownChoice(idMarkupAlignement, listeAlignement));
    			}
    			
    			
    		};
    		positionZoneListView.setReuseItems(true);
    		form.add(positionZoneListView);
    		
    		
    		add(form);
    
    	}
    Merci d'avance pour votre aide

  2. #2
    Membre expérimenté

    Inscrit en
    Décembre 2004
    Messages
    584
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 584
    Points : 1 374
    Points
    1 374
    Par défaut
    bonjour Reno17

    petite question préliminaire: préférez vous une réponse courte et rapide qui donne direct la solution ou plutôt une aide afin d'arriver vous même aux bonnes conclusions ?

    à défaut je tente toujours une approche qui se veut éducative (lol) et donc peut être rébarbative/lente...

    quoiqu'il en soit, regardons le problème: la ListView se base sur cela :
    new CompoundPropertyModel(new LoadableDetachableModel()(..)

    le LoadableDetachableModel implique que le modèle est rechargé, à chaque RequestCycle, lors du premier getObject().

    A la fin de la RequestCycle, le résultat du chargement initial, mis dans le champ transientModelObject du LoadableDetachableModel, est passé à null via la méthode detach() (tous les composants implémentant org.apache.wicket.model.IDetachable voient leur méthode detach appelée en fin de RequestCycle).

    L'idée est de gagner sur la taille de la page sérialisée qui est stockée entre chaque RequestCycle.

    Les RequestCycle sont tout aller/retour client/serveur, lors d'un affichage, d'un clic sur un lien ou d'un submit.

    Au final, le LoadableDetachableModel n'est guère conseillé au sein d'un formulaire, de peur de perdre des changements en cours de route.

    A propos de la ListView, je conseille également de regarder du coté de la méthode setReuseItems, toujours utile dans des formulaires.
    Merci d'utiliser le bouton [Résolu] pour les sujets qui le sont.
    [pub]mon blog franco anglais, article du moment: Wicket: fournir des données JSON via Ajax[/pub]

  3. #3
    Membre à l'essai
    Inscrit en
    Novembre 2009
    Messages
    13
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 13
    Points : 10
    Points
    10
    Par défaut
    Bonjour Joseph,

    J'ai re testé l'écran en n'utilisant pas de loadableDetachableModel et ça marche ! Bon ça me semble un peu magique tout ça

    Avec le loadableDetachableModel, j'arrivais à récupérer la saisie utilisateur de mon
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <input wicket:id="templatePageBean.nom" type="text" id="nom" value="nom"></input>
    . Pourquoi mon textbox s'en sort avec un modele detachable et pas ma listView ?

  4. #4
    Membre expérimenté

    Inscrit en
    Décembre 2004
    Messages
    584
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 584
    Points : 1 374
    Points
    1 374
    Par défaut
    Citation Envoyé par Reno17 Voir le message
    J'ai re testé l'écran en n'utilisant pas de loadableDetachableModel et ça marche ! Bon ça me semble un peu magique tout ça
    En fait, ce qu'on peut réussir avec les modèles est vraiment très fort, voir même parfois un peu surprenant. Mais sur le fond, rien de magique, tout s'explique:

    Citation Envoyé par Reno17 Voir le message
    Avec le loadableDetachableModel, j'arrivais à récupérer la saisie utilisateur de mon
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <input wicket:id="templatePageBean.nom" type="text" id="nom" value="nom"></input>
    . Pourquoi mon textbox s'en sort avec un modele detachable et pas ma listView ?
    Pour faire simple et éviter les soucis: ne pas utiliser le loadableDetachableModel pour l'édition.

    Pour faire long et précis:
    en fait, je pense qu'il y a une "race condition". En effet, tout dépend de l'ordre dans lequel:
    - le modèle est rechargé (au premier getObject())
    - le modèle est mis à jour (via setObject())
    - quand les modifications sont sauvées en DB

    en effet, que voit on dans le LDM:
    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
     
    	public void setObject(final T object)
    	{
    		attached = true;
    		transientModelObject = object;
    	}
    public T getObject()
    	{
    		if (!attached)
    		{
    			attached = true;
    			transientModelObject = load();
     
    			if (log.isDebugEnabled())
    			{
    				log.debug("loaded transient object " + transientModelObject + " for " + this +
    					", requestCycle " + RequestCycle.get());
    			}
     
    			onAttach();
    		}
    		return transientModelObject;
    	}
    autrement dit, si ton composant commence par se mettre à jour et enchaine sur la mise à jour de son modèle, alors le LDM ne pose pas de problème au sein de la même RequestCycle.

    Pour le TextField, c'est le cas.

    Cela se fait lorsqu'un utilisateur soumet le formulaire, et là Wicket cascade un appel à toutes les méthodes qui implémentent IFormModelUpdateListener.

    Le TextField, dans ce cas là, ne regarde pas ce qu'il y a dans son modèle, mais, juste, convertit son entrée via convertInput() et met à jour son modèle.

    La ListView elle procède différemment. Pour connaitre la liste de ses éléments, elle fait d'abord un getObject sur son modèle. Dans le cas d'un LoadableDetachableModel (LDM pour les intimes ), cela implique un rechargement des données. Quand en plus de cela les items de la ListView ne sont pas réutilisés (via setReuseItems), la ListView se contente alors de tous les re créer et réafficher. La modification est donc "perdue".

    A noter que pour le cas du TextField, le LDM n'est toujours pas parfait.

    En effet, il se pourrait qu'un autre élément appelle son getObject avant, rendant la valeur actuelle caduque.

    Par ailleurs, la conversion du rawInput vers le modèle n'est pas systématique, cf
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    	/**
             * Used by Form to tell the FormComponent that a new user input is available
             */
    	public final void inputChanged()
    => lors du RequestCycle où le changement a eu lieu, il est visible, mais si la page est ré affichée pour des raisons X ou Y (erreur de validation par exemple), alors le changement sera perdu. Seule sauvegarde intermédiaire est susceptible de changer la chose, vu qu'alors le prochain reload trouvera ses petits. Mais ce n'est pas une façon propre de faire un formulaire AMHA.

    Ai je été clair ?

    Comme dit au début, j'ai tenté de donner un max de détail. En pratique, le concept même du LDM, avec rechargement de données, le rend incompatible avec l'édition si chaque changement n'est pas immédiatement sauvé.

    On aura plutot tendance à utiliser des instances de la classe Model, via Model.of() ou Model.ofList et ainsi de suite.

    En fait, une stratégie globale peut être:
    - avoir un modèle persistent (un Model par exemple, avec persistance via Serialization entre les RequestCycle) au niveau du formulaire lui même
    - des PropertyModel pour chaque composant se basant sur le modèle du formulaire

    ca fait beaucoup tout ça d'un coup je crains..

    ne pas hésiter à poser des questions!


    nb: merci de cliquer sur résolu si approprié
    Merci d'utiliser le bouton [Résolu] pour les sujets qui le sont.
    [pub]mon blog franco anglais, article du moment: Wicket: fournir des données JSON via Ajax[/pub]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [VB.net]inserer un treeview dans une listview
    Par mich@ dans le forum VB.NET
    Réponses: 1
    Dernier message: 13/03/2007, 20h21
  2. [VB6] Supprimer un enregistrement dans une ListView ??
    Par Argonz dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 14/11/2002, 09h37
  3. Une gauge dans un ListView
    Par Thom@s dans le forum Composants VCL
    Réponses: 3
    Dernier message: 22/10/2002, 10h32
  4. [VB6] [Excel] Insérer une image dans une feuille
    Par mathias dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 09/10/2002, 07h44
  5. Inserer Un Menu dans un autre en execution
    Par apt dans le forum Composants VCL
    Réponses: 2
    Dernier message: 12/08/2002, 11h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo