Utilisation des structures de données Flex DataGrid et imbriquées

Il arrive souvent que les données devant être visualisées / présentées dans un Flex DataGrid proviennent d'un fichier XML ou JSON avec plusieurs niveaux d'imbrication. Malheureusement, par défaut, Flex DataGrid vous permet d'afficher uniquement des tableaux d'objets imbriqués à un seul niveau..

Ce tutoriel montre comment étendre la classe Flex DataGrid pour prendre en charge des structures de données plus complexes. Il vous montrera également comment rendre toutes les colonnes triables, même en utilisant des structures de données imbriquées..




introduction

Ce tutoriel suppose que vous connaissiez les bases de Flex, comment utiliser Flex Builder et comment écrire des fichiers MXML. Une copie de Flex Builder doit être installée sur votre système..

Étape 1: Configuration du projet Flex

La première étape consiste à configurer le projet dans Flex Builder. Créez un nouveau projet dans Flex Builder avec nom du projet comme "NestedDataGrid" et Type d'application sous "application Web (s'exécute dans Flash Player)". Laissez toutes les autres options à leurs valeurs par défaut et cliquez sur Terminer.

Étape 2: Importer des exemples de données

Les données que nous allons afficher dans le DataGrid sont obtenues à partir d'un fichier XML. Créez un dossier dans votre dossier 'src' appelé 'assets' et mettez les données indiquées ci-dessous dans un fichier nommé 'meetings.xml'. Sinon, vous pouvez télécharger le fichier XML à partir d'ici et le placer dans le dossier "assets"..

    haute  Lisa Green [email protected] +330-7593  12 juillet 2009  Chambre 405   moyen  Christopher Martin [email protected] +330-7553  14 juillet 2009  Chambre 405   haute  George Rodriguez [email protected] +330-7502  18 juillet 2009  Chambre 771   haute  Jennifer Parker [email protected] +330-5380  20 août 2009  Chambre 562  

Étape 3: Créer l'interface

Voici une description rapide de la construction de l'interface pour afficher les données et les valeurs d'ID appropriées requises pour le code dans ce tutoriel:

  1. Ouvrez le fichier NestedDataGrid.mxml et accédez à la vue Création.
  2. Faites glisser et déposez un "Panneau" dans la vue Composants. Définissez son identifiant sur "meetingsPanel" et son titre sur "Réunions"
  3. Définissez la hauteur et la largeur du panneau sur 500 et définissez les valeurs X et Y sur 0.
  4. Glissez et déposez un 'DataGrid' sur le panneau
  5. Définissez les valeurs X et Y sur 10
  6. Définissez la largeur sur meetingsPanel.width-40 et la hauteur sur 45%
  7. Accédez à la vue source et dans la balise 'mx: Appication', ajoutez l'attribut layout = "vertical".

Votre interface devrait ressembler à celle montrée dans l'image ci-dessous:

Le MXML dans la vue source devrait ressembler à ceci:

            

Lecture dans le fichier XML

Dans les trois prochaines étapes, nous créons un composant HTTPService, lisons les données du fichier XML et les stockons dans une variable locale. Cela se fait en trois étapes:

Étape 4: Créez le composant HTTPService

Basculez vers la vue Source du fichier MXML et ajoutez le code suivant juste en dessous de la mx: application étiquette:

 

La fonction httpResultHandler () sera appelée lorsque les données auront été extraites. S'il y a une erreur lors de l'extraction des données, la fonction httpFaultHandler () est appelée. Notez que ceci ne crée que l'objet HTTPService, les données doivent être récupérées par un appel de fonction explicite (voir sous-étape 3).

Étape 5: httpResultHandler () et httpFaultHandler ()

Ajouter un mx: script tag juste en dessous de la mx: application étiquette. À l'intérieur de celui-ci, définissez la variable qui contiendra les données entrantes et les fonctions permettant de gérer les événements du composant HTTPService. Le code à faire qui ressemble à ceci:

 importer mx.rpc.events.FaultEvent; importer mx.rpc.events.ResultEvent; importer mx.collections.ArrayCollection; import mx.controls.Alert; [Bindable] public var dataForGrid: ArrayCollection; fonction privée httpResultHandler (event: ResultEvent): void dataForGrid = event.result.meetings.meeting;  fonction privée httpFaultHandler (event: FaultEvent): void Alert.show ("Une erreur s'est produite lors de l'obtention de la chaîne"); 

La variable 'dataForGrid' contient les données que nous allons lire. La balise '[Bindable]' garantit que chaque fois que les données changent (lorsqu'elles sont lues), le contrôle DataGrid est mis à jour en conséquence. Le code XML est lu en tant qu'objet transmis à travers l'événement 'ResultEvent' et 'event.result.meetings.meeting' accède à l'ArrayCollection des objets 'meeting'..

Étape 6: Obtenir les données du fichier XML

Dans cette étape, l'appel de fonction réel pour obtenir les données XML est effectué. Une fonction intialize est affectée à l'événement qui est déclenché à chaque chargement de l'application - l'événement 'creationComplete'. Ajouter l'attribut creationComplete = "getData ()" dans la balise 'mx: Application' et définissez la fonction 'getData ()' comme ci-dessous (à ajouter après la fonction 'httpFaultHandler'):

 fonction privée getData (): void readXML.send (); 

Cela permet à l'objet HTTPService d'extraire les données du fichier. Une fois les données extraites, l'événement 'result' est déclenché et appelle la fonction 'httpResultHandler ()'. S'il y a un problème pour obtenir les données, l'événement 'fault' est déclenché et appelle la fonction httpFaultHandler ()..

Étape 7: Jalon

À ce stade, votre fichier NestedDataGrid.mxml devrait ressembler à ceci:

                

Étape 8: DataGrid avec des données non imbriquées

Je vais simplement expliquer brièvement pourquoi les données imbriquées posent des problèmes d’affichage, en montrant d’abord comment vous affichez des données non imbriquées. Supposons que, dans le fichier XML ci-dessus, vous vouliez uniquement afficher la date, le lieu et la priorité des réunions (et non les informations du présentateur). Le code ci-dessous sera capable de l'afficher sans aucun problème (le contenu de 'mx: Panel' est présenté ici. Tous les autres codes sont identiques):

        

Le résultat de ceci serait l'application suivante:


Notez que l'attribut dataProvider du DataGrid peut être directement affecté à l'objet 'dataForGrid' de ArrayCollection et que chaque DataGridColumn se voit attribuer un attribut dataField qui correspond directement au nom de la propriété. Cependant, supposons que vous souhaitiez accéder au nom du présentateur. Vous pouvez y accéder en tant que "présentateur.nom". Si vous essayez de donner cette valeur à 'dataField', vous obtiendrez une erreur. En effet, Flex ne prend pas en charge les objets imbriqués par défaut. Lisez la suite pour apprendre à résoudre ce problème en étendant la classe DataGridColumn et en écrivant votre propre code pour gérer ce cas..

Étape 9: Création de la classe NestedDataGridColumn

Nous redéfinissons certaines fonctions de la classe de colonnes DataGrid pour contourner le problème décrit ci-dessus. Commencez par créer un dossier dans le répertoire 'src' appelé 'classes'. Créez une nouvelle "classe ActionScript" dans ce dossier, nommée "NestedDataGridColumn". Dans le champ 'Superclasse', cliquez sur 'Parcourir…' et sélectionnez 'DataGridColumn' dans la liste qui apparaît. Laissez tout le reste aux valeurs par défaut et cliquez sur 'Terminer'. Un nouveau fichier doit avoir été créé et rempli avec le code suivant:

 classes de package import mx.controls.dataGridClasses.DataGridColumn; Classe publique NestedDataGridColumn étend DataGridColumn fonction publique NestedDataGridColumn (columnName: String = null) super (columnName); 

Étape 10: Déclaration de la propriété 'nestedDataField'

Dans la classe NestedDataGridColumn, ajoutez une variable publique pouvant être liée appelée "nestedDataField". Nous allons utiliser cela à la place de la propriété par défaut 'dataField' pour transmettre le nom du champ. C’est vital, car si la propriété par défaut 'dataField' est utilisée, une erreur disant Erreur: les critères de recherche doivent contenir au moins une valeur de champ de tri.. se produira lorsque nous essaierons de trier le DataGrid après avoir défini la fonction de tri personnalisée ultérieurement.

Étape 11: Redéfinir la fonction 'itemToLabel'

Comme vous pouvez le constater, la nouvelle classe que nous avons créée a déjà été renseignée avec un constructeur. Laissez le constructeur tel quel et ajoutez en dessous la fonction suivante:

 redéfinit la fonction publique itemToLabel (data: Object): String var fields: Array; var label: String; var dataFieldSplit: String = nestedDataField; var currentData: Object = data; // vérifie si la valeur nestedDataField contient un '.' (c'est-à-dire accède à une valeur imbriquée) if (nestedDataField.indexOf (".")! = -1) // récupère tous les champs qui doivent être consultés fields = dataFieldSplit.split ("."); for each (var f: Chaîne dans les champs) // parcourt les champs un par un et obtient la valeur finale, en approfondissant un champ à chaque itération currentData = currentData [f]; if (currentData is String) // renvoie la valeur finale return String (currentData);  // s'il n'y a aucune imbrication impliquée else if (dataFieldSplit! = "") currentData = currentData [dataFieldSplit];  // si notre méthode n'a pas fonctionné comme prévu, appelez la fonction par défaut try label = currentData.toString ();  catch (e: Error) label = super.itemToLabel (data);  // retourne le résultat retour label; 

La redéfinition de la fonction 'itemToLabel' est la clé pour pouvoir accéder aux données imbriquées dans votre grille de données. La fonction itemToLabel contrôle ce qui est affiché dans les lignes DataGrid. Nous l'utilisons donc ici pour demander à Flex d'afficher les données imbriquées de la manière que nous avons spécifiée..

Comme vous pouvez le constater, la définition de la fonction commence par le mot-clé 'override', ce qui signifie que la fonction prédéfinie par défaut du même nom est remplacée au profit de la fonction que vous avez définie. Chaque déclaration est expliquée dans les commentaires. En résumé, la fonction vérifie si les champs de données imbriqués sont utilisés (si un "." Est présent). Si tel est le cas, obtenez le nom de chaque champ de données et effectuez une itération dans le fournisseur de données, en approfondissant chaque étape en accédant au champ enfant..

La fonction "itemToLabel" est appelée par Flex avec un argument contenant l'arrayCollection spécifié en tant que fournisseur de données dans le composant dataGrid. Tous les attributs de NestedDataGridColumn (lorsqu'il est utilisé dans le fichier mxml) sont directement accessibles et toute valeur publique définie dans cette classe peut recevoir une valeur dans le MXML. Dans notre fichier NestedDataGrid.mxml, nous remplaçons les composants 'mx: DataGridColumn' par le composant 'classes: NestedDataGridColumn', et affectons les éléments spécifiques que nous souhaitons afficher dans les colonnes à l'attribut 'nestedDataField' (qui a été déclaré dans la ' Fichier NestedDataGridColumn.as). Le DataGridColumn devrait maintenant ressembler à ceci:

          

Notez que je spécifie directement la propriété 'nestedDataField' en tant que "présentateur.nom" et "présenter.phone" ici. De plus, j'ai ajouté des largeurs aux colonnes et défini la largeur du composant 'mx: Panel' à 600px pour un meilleur affichage. J'ai ajouté la propriété 'sortable' à false pour les deux nouvelles colonnes. Si vous supprimez ceci (ou le définissez sur true) et exécutez le programme, la colonne ne sera pas triée. Nous allons résoudre cela dans la prochaine étape en définissant notre propre fonction de tri. Pour l'instant, l'application devrait ressembler à ceci:


Étape 12: écriture de la fonction de tri personnalisé

Il ne reste plus qu’à définir la fonction de tri personnalisé afin que le tri soit également activé dans tous les champs (par exemple, vous souhaitez trier les noms des présentateurs par ordre alphabétique). Ajoutez la fonction appelée 'mySortCompareFunction' sous la fonction 'itemToLabel' comme donnée:

 fonction privée mySortCompareFunction (obj1: Object, obj2: Object): int var fields: Array; var dataFieldSplit: String = nestedDataField; var currentData1: Object = obj1; var currentData2: Object = obj2; if (nestedDataField.indexOf (".")! = -1) fields = dataFieldSplit.split ("."); pour chaque (var f: chaîne dans les champs) currentData1 = currentData1 [f]; currentData2 = currentData2 [f];  else if (dataFieldSplit! = "") currentData1 = currentData1 [dataFieldSplit]; currentData2 = currentData2 [dataFieldSplit];  if (currentData1 est int && currentData2 est int) var int1: int = int (currentData1); var int2: int = int (currentData2); var résultat: int = (int1> int2)? - 1: 1; retourne le résultat;  if (currentData1 est String && currentData2 est String) currentData1 = String (currentData1); currentData2 = String (currentData2); return (currentData1> currentData2)? - 1: 1;  if (currentData1 est Date && currentData2 est Date) var date1: Date = currentData1 as Date; var date2: Date = currentData2 comme Date; var date1Timestamp: Number = currentData1.getTime (); var date2Timestamp: Number = currentData2.getTime (); return (date1Timestamp> date2Timestamp)? - 1: 1;  retourne 0; 

Cette fonction sera appelée par Flex avec deux objets et devrait renvoyer -1.0 ou 1 selon que le premier objet est supérieur, égal ou inférieur au deuxième objet, respectivement. Flex prend en charge le tri proprement dit.

Cette fonction utilise la même logique que la fonction 'itemToLabel' pour obtenir la valeur imbriquée appropriée. Puis, selon le type de valeur (int, String ou Date), il la compare de manière appropriée et renvoie -1 si 'currentData1' est supérieur à 'currentData2', 0 s'il est égal, et 1 si 'currentData2. 'est supérieur à' currentData1 '.

Étape 13: Connexion de la fonction de tri personnalisé

Si vous avez remarqué, 'customSortCompareFunction' n'est pas une fonction prédéfinie dans la classe DataGridColumn que nous substituons. Cette fonction doit être affectée comme fonction de tri d'une manière différente. Nous devons affecter à la variable prédéfinie 'sortCompareFunction' le nom de la fonction de tri, qui est 'customSortCompareFunction' dans notre cas. Cela devrait être fait à l'intérieur du constructeur. Le constructeur ressemble maintenant à ceci:

 fonction publique NestedDataGridColumn (columnName: String = null) // la fonction de tri personnalisée étant affectée à la variable prédéfinie sortCompareFunction = mySortCompareFunction; super (nomcolonne); 

Une fois que cela est fait, vous êtes tous ensemble. Vous avez maintenant une classe personnalisée qui peut gérer des données imbriquées de manière arbitraire à afficher dans un DataGrid. Et vous pouvez trier la grille comme vous le souhaitez.

Conclusion

Aujourd'hui, vous avez appris à contourner une limitation de la classe FlexDataGrid pour obtenir des données imbriquées de manière arbitraire et à les afficher dans un DataGrid. Vous avez également appris à définir votre propre fonction de tri pour que la grille reste triable. Vous pouvez maintenant utiliser ce NestedDataGridColumn dans toutes vos applications sans surcharge.

Vous pouvez également étendre la fonction 'itemToLabel' pour inclure d'autres formats d'accès arbitraires, comme l'accès aux tableaux à l'intérieur des objets enfants ou l'accès aux attributs xml. Vous pouvez également étendre davantage la fonction de tri pour trier d'autres types de données. Vous pourrez également ajouter d'autres fonctionnalités telles que la coloration des lignes en fonction de la priorité de la réunion et l'affichage de détails supplémentaires sur le présentateur en cliquant sur une ligne..

Merci d'avoir lu :)