Apache Adobe Flex TutorialTutoriaux Adobe Flex & AIR en Français

12août/096

Flex DataGrid – Sélection de lignes dans un Datagrid avec des Checkbox

Tutorial Flex écrit par Vincent Le Gallic (www.frianbiz.com). Publiez vous aussi sur flex-tutorial!

Un Datagrid supporte par défaut la multi-sélection grâce à la propriété allowMultipleSelection. Cependant l’utilisation du Ctrl+click pour sélectionner plus d'un item à la fois n’est pas toujours adaptée. Comme dans l’interface de Gmail (réputée conviviale et pratique) la multi sélection peut être gérée grâce à une case à cocher attribuée à chaque item de la liste. Voici une façon de mettre en place cette technique en Flex :

Tous les objets affichés dans le Datagrid doivent avoir une propriété qui vous permettra de savoir si la ligne est sélectionnée ou pas. Dans l’exemple ci-dessous cette propriété se nomme « selected »

<mx:Object songId="0" title="Astronaut" artist="David Byrne" selected="false"/>

Cette propriété est fixée et utilisée directement dans la donnée car les itemRenderer que l'on va utiliser ensuite ont un mécanisme de recyclage. Il nous faut donc un emplacement où garder cette valeur en mémoire. La donnée remplit parfaitement ce rôle.

Pour commencer il faut ajouter une colonne au Datagrid qui contiendra un inline item renderer. On peut ensuite ajouter notre Checkbox. La propriété selected de la Checkbox (qui définit si notre case est cochée ou pas) sera liée à la propriété selected des items du datagrid de la façon suivante :

<mx:CheckBox selected="{data.selected}"/>

Il faut ensuite écouter les changements d’état lorsqu’on clic sur la checkBox :

<mx:CheckBox selected="{data.selected}" click="{data.selected=!data.selected}"/>

On met à jour la propriété selected  de l’item afin d’éviter tout  affichage aléatoire du à l’utilisation d’un itemRenderer dans un Datagrid.

En plus de cela, on va ajouter à notre application une liste des éléments sélectionnés.

En même temps que le basculement de la valeur de data.selected, on informe aussi notre application qu'un changement a été effectué. Pour cela, il faut passer par outerDocument car on se trouve dans un itemRenderer qui a son propre scope:

<mx:CheckBox label="" selected="{data.selected}" click="{data.selected=!data.selected;outerDocument.onItemChanged(data)}"/>

Pour plus d'explications sur ces échanges application/item renderer, vous pouvez consulter cet article:

Flex Item Renderer - Item Renderer utilisant des composants personnalisés MXML (Inline)

Au click sur la CheckBox, on appelle une méthode onItemChanged(event), qui va mettre à jour la liste des éléments sélectionnés. On met à jour les données du dataProvider à chaque modification pour éviter de  boucler sur le dataProvider de notre DataGrid lorsque l’on souhaite récupérer toutes les lignes sélectionnées.

On ajoute aussi à notre application, une CheckBox permettant de sélectionner/déselectionner tous les éléments, simplement en bouclant sur les éléments du dataProvider et en fixant la propriété selected à true ou false. On appelle ensuite la méthode refresh() de la classe ArrayCollection pour mettre à jour le visuel.

Ci-dessous un exemple complet:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" viewSourceURL="srcview/index.html">
	<mx:Script>
	<![CDATA[
	import mx.controls.CheckBox;
	import mx.collections.ArrayCollection;
	[Bindable]
	public var listeItemSelected : ArrayCollection = new ArrayCollection;

	public function cbAllHandler(evt : Event):void{
		listeItemSelected.removeAll();

		for each (var item:Object in dp){
			item.selected = cbAll.selected;
			if(item.selected){
				listeItemSelected.addItem(item);
			}
		}
		dp.refresh();
	}
	public function onItemChanged(item : Object):void{
		//Si l'item n'est pas déja dans la liste
		if(listeItemSelected.getItemIndex(item)==-1) {
			//on l'ajoute
			listeItemSelected.addItem(item);
		}else{
			listeItemSelected.removeItemAt(listeItemSelected.getItemIndex(item)); //sinon on le supprime
		}
	}
	]]>
	</mx:Script>
	<mx:ArrayCollection id="dp">
		<mx:Array>
			<mx:Object songId="0" title="Astronaut" artist="David Byrne" selected="false"/>
			<mx:Object songId="1" title="Rio" artist="Duran Duran" selected="false"/>
			<mx:Object songId="2" title="Enjoy The Silence" artist="Depeche Mode" selected="false"/>
			<mx:Object songId="3" title="Mesopotamia" artist="B-52s" selected="false"/>
		</mx:Array>
	</mx:ArrayCollection>
	<mx:HBox>
		<mx:VBox width="100%" height="100%">
			<mx:CheckBox id="cbAll" label="{(cbAll.selected)?'tout décocher':'tout cocher'}" change="cbAllHandler(event)"/>
			<mx:DataGrid dataProvider="{dp}" y="26" height="142">
				<mx:columns>
					<mx:DataGridColumn width="25" paddingLeft="5" paddingRight="5">
						<mx:itemRenderer>
							<mx:Component>
								<mx:CheckBox label="" selected="{data.selected}" click="{data.selected=!data.selected;outerDocument.onItemChanged(data)}"/>
							</mx:Component>
						</mx:itemRenderer>
					</mx:DataGridColumn>
					<mx:DataGridColumn headerText="Titre" dataField="title"/>
					<mx:DataGridColumn headerText="Artist" dataField="artist"/>
				</mx:columns>
			</mx:DataGrid>
			<mx:Label text="{dp.length+' résultat(s) '+listeItemSelected.length+' item(s) sélectionné(s)' }" />
		</mx:VBox>
		<mx:List labelField="title"  dataProvider="{listeItemSelected}" height="142"></mx:List>
	</mx:HBox>
</mx:Application>

Flex Source Code Download: Télécharger le code source complet de l'application

This movie requires Flash Player 11

Articles similaires

Commentaires (6) Trackbacks (0)
  1. Bonjour,

    Magnifique utilitaire, et très clairement expliqué, merci à Vincent Le Gallic. J'ai intégré avec succès ce code dans une application de calendrier partagé que je développe pour mon école.

    Je cherche à ajouter une petite fonctionnalité supplémentaire depuis quelques jours, mais je n'y arrive pas. Peut-être l'auteur (ou quelqu'un-e d'autre) pourrait-il(elle) m'aider.

    En fait, au chargement de mon application, une requête (php/amfphp/mySql) remplit la liste 'listeItemSelected' avec des informations (événement createComplete). Du coup, j'ai déjà des éléments dans cette liste dès le départ, avant que l'utilisateur puisse cocher ou décocher à volonté. Dès lors, je souhaiterais que les cases à cocher correspondantes aux éléments chargés s'activent dans la DataGrid au démarrage de l'application, mais je n'arrive pas à pointer sur les checkbox car elles n'ont pas d'identifiant. Pour prendre l'exemple de l'article ci-dessus, c'est comme si 'Duran Duran' et 'Depeche Mode' était chargé dans la liste 'listeItemSelected' au chargement de l'appli et que cela déclenchait la mise sur "true" des checkbox correspondantes dans la DataGrid 'dp'.

    Merci mille fois de vos idées et propositions de solutions.

    Alain

  2. Bonjour,
    si dans votre donnée, la valeur "selected" de chaque objet est déjà fixée (à true ou à false), les checkbox sera initialisée dans le bon état grâce au Binding (selected="{data.selected}"). non?

    Fabien

  3. Bonjour Fabien,

    Bravo pour votre blog, c'est une mine d'or, et merci pour votre réponse.

    En fait, mon problème venait du fait que ma DataGrid (nourrie par une ArrayCollection formée à partir d'une requête php/mysql) ne contenait pas de champ 'selected'. Grâce à votre remarque, j'ai pu cerner le problème... et l'ai résolu en bouclant le tableau source à l'intérieur du tableau contenant les checkbox

    Actionscript:
    1. for (var c:Number=0; c&lt;dp.length; c++)
    2.     {
    3.         for (var d:Number=0; d&lt;listeItemSelected.length; d++)
    4.         {
    5.             if (dp.getItemAt(c).libelleProblematique == listeItemSelected.getItemAt(d).libelleProblematique)
    6.             {
    7.                 dp.getItemAt(c).selected = "true";
    8.             }
    9.         }
    10.        
    11.     }

    Merci encore mille fois et meilleures salutations.

    Alain

  4. Bonjour,

    J'ai fais un datagrid avec des checkbox mais d'une manière un peu differente de la votre. En fait, je récupère les données d'une BDD que j'affiche dans mon grid, mais je n'ai pas de champ selected dans mes données pour gérer la checkbox. Quand, je coche un element de mon datagrid, je l'enregistre dans une liste (listElementsSelectionnes) et inversement. Et quand, je sauvegarde mes elements modifiés en base, je vide cette liste. Et ce que je voudrais aussi faire c'est reinitialiser les checkbox cochées de mon datagride à décochées mais je n'y arrive pas.

    Voici mon code :

    Actionscript:
    1. [Bindable]
    2. public var listElementsSelectionnes:ArrayCollection=new ArrayCollection();
    3.  
    4.  
    5.  
    6. //permet de gérer les éléments séléctionnés dans le datagrid à l'aide la checkbox
    7. public function gererSelectionElement(check:Boolean):void
    8. {
    9.                 //si un element du datagrid est coché, on l'ajoute dans listElementsSelectionnes.
    10.                 //A l'inverse si un element est décoché, on le supprime de listElementsSelectionnes
    11.                 if(check==true)
    12.                 {
    13.                     listElementsSelectionnes.addItem(dataGrid.selectedItem);
    14.                 }
    15.                 else
    16.                 {
    17.                    listElementsSelectionnes.removeItemAt(listElementsSelectionnes.getItemIndex(dataGrid.selectedItem));
    18.                 }   
    19. }
    20.  
    21. private function saveElement():void 
    22. {
    23.       //declenche evenement pour sauvegarde en base
    24.             var addEvent:SaveOrUpdateListeLocationsEvent=new SaveOrUpdateListeLocationsEvent(listElementsSelectionnes);
    25.             addEvent.dispatch();
    26.            
    27.             //vide ma liste d'elements selectionnés
    28.             listElementsSelectionnes.removeAll();
    29.            
    30.             //je souhaiterai réinitialiser mes checkbox cochées à décochées
    31. }

    MXML:

    Merci,

    Jeremy.

  5. Bonsoir,

    Tout d'abord je voudrai vous remercier pour votre travail. Grâce a vous je ne suis paniqué lorsque je suis bloqué avec Flex. Voilà je voudrais savoir comment faire pour mettre un datagrid ayant une grande largeur dans un conteneur (un bordercontener de préférence) de largeur plus petite. Merci d'avance.

  6. J'ai oublier de mentionner que le conteneur en question aura alors un scroller horizontal ( chose que je ne sait pas faire)


Leave a comment

(required)

Aucun trackbacks pour l'instant