Lavorare con Flex DataGrid e strutture dati nidificate

Accade spesso che i dati che devono essere visualizzati / presentati in Flex DataGrid provengano da un file XML o JSON con più di un livello di nidificazione. Sfortunatamente, per impostazione predefinita, Flex DataGrid consente di visualizzare solo matrici di oggetti nidificati a livello singolo.

Questo tutorial mostra come estendere la classe Flex DataGrid per ospitare strutture di dati più complesse. Mostrerà anche come rendere tutte le colonne ordinabili, anche quando si utilizzano strutture dati nidificate.




introduzione

Questo tutorial presume che tu conosca le basi di Flex, come utilizzare Flex Builder e come scrivere file MXML. Dovresti avere una copia di Flex Builder installato sul tuo sistema.

Passaggio 1: installazione del progetto Flex

Il primo passo è impostare il progetto in Flex Builder. Crea un nuovo progetto in Flex Builder con Nome del progetto come "NestedDataGrid" e Tipo di applicazione come "Applicazione Web (eseguita in Flash Player)". Lascia tutte le altre opzioni ai valori predefiniti e fai clic su Fine.

Passaggio 2: Importa dati di esempio

I dati che mostreremo in DataGrid sono ottenuti da un file XML. Crea una cartella nella cartella 'src' chiamata 'assets' e inserisci i dati mostrati di seguito in un file chiamato 'meetings.xml'. In alternativa, puoi scaricare il file XML da qui e metterlo nella cartella 'assets'.

    alto  Lisa Green [email protected] +330-7593  12 luglio 2009  Camera 405   medio  Christopher Martin [email protected] +330-7553  14 luglio 2009  Camera 405   alto  George Rodriguez [email protected] +330-7502  18 luglio 2009  Stanza 771   alto  Jennifer Parker [email protected] +330-5380  20 agosto 2009  Stanza 562  

Passaggio 3: crea l'interfaccia

Ecco una breve ripartizione della costruzione dell'interfaccia per visualizzare i dati e i valori ID appropriati richiesti per il codice in questo tutorial:

  1. Aprire il file NestedDataGrid.mxml e andare alla vista di progettazione
  2. Trascina e rilascia un "Pannello" dalla vista Componenti. Imposta il suo ID su "meetingsPanel" e il titolo su "Riunioni"
  3. Imposta l'altezza e la larghezza del pannello su 500 e imposta i valori X e Y su 0
  4. Trascina e rilascia una "DataGrid" sul pannello
  5. Impostare i valori X e Y su 10
  6. Imposta la larghezza su meetingsPanel.width-40 e l'altezza al 45%
  7. Vai alla vista sorgente e nel tag 'mx: Appication' aggiungi il layout degli attributi = "verticale"

La tua interfaccia dovrebbe essere simile a quella mostrata nell'immagine qui sotto:

L'MXML nella vista sorgente dovrebbe apparire così:

            

Lettura nel file XML

Nei prossimi tre passaggi, creiamo un componente HTTPService, leggiamo i dati dal file XML e li memorizziamo in una variabile locale. Questo viene fatto in tre fasi:

Passaggio 4: creare il componente HTTPService

Passa alla visualizzazione Source del file MXML e aggiungi il seguente codice subito sotto mx: Application etichetta:

 

La funzione httpResultHandler () verrà chiamata quando i dati sono stati recuperati. Se si verifica un errore nel recupero dei dati, viene chiamata la funzione httpFaultHandler (). Si noti che questo crea solo l'oggetto HTTPService, i dati devono essere recuperati da una chiamata di funzione esplicita (vedere sub-step 3)

Passaggio 5: httpResultHandler () e httpFaultHandler ()

Aggiungi un mx: Script etichetta appena sotto il mx: Application etichetta. Al suo interno, definire la variabile che manterrà i dati in entrata e le funzioni per gestire gli eventi dal componente HTTPService. Il codice per farlo sembra così:

 import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.collections.ArrayCollection; import mx.controls.Alert; [Bindable] public var dataForGrid: ArrayCollection; funzione privata httpResultHandler (event: ResultEvent): void dataForGrid = event.result.meetings.meeting;  funzione privata httpFaultHandler (event: FaultEvent): void Alert.show ("Errore durante il recupero della stringa"); 

La variabile 'dataForGrid' contiene i dati che stiamo per leggere. Il tag '[Bindable]' fa in modo che ogni volta che i dati cambiano (quando viene letto), DataGrid viene aggiornato di conseguenza. L'XML viene letto come un oggetto che viene passato attraverso l'evento 'ResultEvent' e 'event.result.meetings.meeting' accede a ArrayCollection di oggetti 'meeting'.

Passaggio 6: Ottieni i dati dal file XML

In questo passaggio, viene eseguita la chiamata alla funzione effettiva per ottenere i dati XML. Una funzione intialize viene assegnata all'evento che viene attivato ogni volta che viene caricata l'applicazione, l'evento 'creationComplete'. Aggiungi l'attributo creationComplete = "getData ()" al tag 'mx: Application' e definire la funzione 'getData ()' come sotto (da aggiungere dopo la funzione 'httpFaultHandler'):

 funzione privata getData (): void readXML.send (); 

Ciò rende l'oggetto HTTPService ottenere i dati dal file. Una volta recuperati i dati, viene attivato l'evento 'risultato' che chiama la funzione 'httpResultHandler ()'. Se si verifica un problema durante il recupero dei dati, viene attivato l'evento "errore", che chiama la funzione httpFaultHandler ().

Step 7: Milestone

A questo punto il tuo NestedDataGrid.mxml dovrebbe assomigliare a questo:

                

Passaggio 8: DataGrid con dati non nidificati

Mi limiterò a sottolineare brevemente perché i dati annidati pongono problemi nella visualizzazione, dimostrando innanzitutto come si mostrano i dati non annidati. Supponiamo, dal file XML sopra, di voler solo mostrare la data, il luogo e la priorità delle riunioni (e non le informazioni del relatore). Il seguente codice sarà in grado di visualizzarlo senza problemi (contenuto di 'mx: Panel' mostrato qui. Tutto il resto è lo stesso):

        

Il risultato di questa sarebbe la seguente applicazione:


Si noti che l'attributo dataProvider di DataGrid può essere assegnato direttamente a 'DataForGrid' di ArrayCollection e ogni DataGridColumn all'interno viene assegnato un attributo dataField che corrisponde direttamente al nome della proprietà. Tuttavia, supponiamo di voler accedere alle informazioni sul nome del relatore, a cui è possibile accedere come "presenter.name". Se provi a dare questo valore al 'dataField' otterrai un errore. Questo perché, Flex non supporta gli oggetti nidificati per impostazione predefinita. Continua a leggere per sapere come risolvere questo problema estendendo la classe DataGridColumn e scrivendo il tuo codice per gestire questo caso.

Passaggio 9: creazione della classe NestedDataGridColumn

Ridefiniamo alcune funzioni nella classe di colonne DataGrid per aggirare il problema descritto sopra. Per prima cosa crea una cartella nella directory 'src' chiamata 'classes'. Crea una nuova "classe ActionScript" in quella cartella, denominata "NestedDataGridColumn". Nel campo "Superclasse", fai clic su "Sfoglia ..." e seleziona "DataGridColumn" dall'elenco che viene visualizzato. Lascia tutto il resto ai valori predefiniti e fai clic su "Fine". Un nuovo file dovrebbe essere stato creato e popolato con il seguente codice:

 package classes import mx.controls.dataGridClasses.DataGridColumn; public class NestedDataGridColumn estende DataGridColumn public function NestedDataGridColumn (columnName: String = null) super (columnName); 

Passaggio 10: dichiarazione della proprietà 'nestedDataField'

Nella classe NestedDataGridColumn, aggiungi una variabile pubblica bindable chiamata 'nestedDataField'. Utilizzeremo questo invece della proprietà predefinita 'dataField' per passare il nome del campo. Questo è fondamentale, perché se viene utilizzata la proprietà predefinita "dataField", viene visualizzato un errore Errore: i criteri di ricerca devono contenere almeno un valore di campo di ordinamento. si verificherà quando tenteremo di ordinare il DataGrid dopo aver definito la funzione di ordinamento personalizzato in seguito.

Passaggio 11: ridefinizione della funzione "itemToLabel"

Come puoi vedere, la nuova classe che abbiamo creato è già stata popolata con un costruttore. Lascia il costruttore così com'è e sotto che aggiungi la seguente funzione:

 sovrascrivi la funzione pubblica itemToLabel (data: Object): String var fields: Array; etichetta var: String; var dataFieldSplit: String = nestedDataField; var currentData: Object = data; // controlla se il valore nestedDataField contiene un '.' (ad esempio, accede a un valore nidificato) if (nestedDataField.indexOf (".")! = -1) // richiama tutti i campi a cui è necessario accedere fields = dataFieldSplit.split ("."); per ogni (var f: Stringa nei campi) // esegue il looping dei campi uno ad uno e ottiene il valore finale, passando ad un campo in profondità ogni iterazione correnteData = currentData [f]; if (currentData is String) // restituisce il valore finale return String (currentData);  // se non vi è alcun nesso coinvolto else if (dataFieldSplit! = "") currentData = currentData [dataFieldSplit];  // se il nostro metodo non ha funzionato come previsto, ricorri a chiamare la funzione predefinita try label = currentData.toString ();  catch (e: Error) label = super.itemToLabel (data);  // restituisce l'etichetta di restituzione dei risultati; 

La ridefinizione della funzione 'itemToLabel' è la chiave per poter accedere ai dati nidificati nel tuo DataGrid. La funzione itemToLabel controlla ciò che viene mostrato nelle righe DataGrid. Quindi lo usiamo qui per chiedere a Flex di mostrare i dati nidificati nel modo che abbiamo specificato.

Come puoi vedere, la definizione della funzione inizia con la parola chiave 'override', il che significa che la funzione predefinita predefinita dello stesso nome viene sovrascritta a favore della funzione che hai definito. Ogni affermazione è spiegata nei commenti. In breve, ciò che fa la funzione è controllare se si accede ai campi di dati nidificati (se è presente un '.'). Se lo è, prendi il nome di ciascun campo di dati e itera attraverso il dataProvider, approfondendo ogni passaggio accedendo al campo secondario.

La funzione 'itemToLabel' è chiamata da Flex con un argomento che contiene ArrayCollection che è stato specificato come dataProvider nel dataGrid. Tutti gli attributi di NestedDataGridColumn (quando viene utilizzato nel file mxml) sono direttamente accessibili e a qualsiasi proprietà pubblica definita in questa classe può essere assegnato un valore in MXML. Nel nostro file NestedDataGrid.mxml, sostituiamo i componenti 'mx: DataGridColumn' con il componente 'classes: NestedDataGridColumn' e assegniamo gli elementi specifici che vogliamo mostrare nelle colonne all'attributo 'nestedDataField' (che è stato dichiarato nel ' NestedDataGridColumn.as 'file). Il DataGridColumn ora dovrebbe assomigliare a questo:

          

Nota che sto specificando direttamente la proprietà 'nestedDataField' come "presenter.name" e "presenter.phone" qui. Inoltre, ho aggiunto larghezze alle colonne e impostato la larghezza del componente 'mx: Panel' a 600px per una migliore visualizzazione. Ho aggiunto la proprietà 'ordinabile' per essere falsa alle due nuove colonne. Se rimuovi questo (o lo imposta a true) ed esegui il programma, la colonna non verrà ordinata. Lo risolveremo nel prossimo passaggio definendo la nostra funzione di ordinamento. Per ora l'applicazione dovrebbe assomigliare a questa:


Passaggio 12: scrittura della funzione di ordinamento personalizzata

L'unica cosa rimasta ora è definire la funzione di ordinamento personalizzato in modo che l'ordinamento sia abilitato anche in tutti i campi (ad esempio, si desidera ordinare i nomi dei presentatori in ordine alfabetico). Aggiungi la funzione chiamata "mySortCompareFunction" sotto la funzione 'itemToLabel' come indicato:

 funzione privata 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 ("."); per ogni (var f: stringa nei campi) currentData1 = currentData1 [f]; currentData2 = currentData2 [f];  else if (dataFieldSplit! = "") currentData1 = currentData1 [dataFieldSplit]; currentData2 = currentData2 [dataFieldSplit];  if (currentData1 è int && currentData2 è int) var int1: int = int (currentData1); var int2: int = int (currentData2); var result: int = (int1> int2)? - 1: 1; ritorno risultato;  if (currentData1 è String && currentData2 è String) currentData1 = String (currentData1); currentData2 = String (currentData2); return (currentData1> currentData2)? - 1: 1;  if (currentData1 è Date && currentData2 è Date) var date1: Date = currentData1 come Date; var date2: Date = currentData2 come Date; var date1Timestamp: Number = currentData1.getTime (); var date2Timestamp: Number = currentData2.getTime (); return (date1Timestamp> date2Timestamp)? - 1: 1;  restituisce 0; 

Questa funzione verrà chiamata da Flex con due oggetti e si prevede che restituisca o -1,0 o 1 a seconda che il primo oggetto sia maggiore di, uguale o inferiore a, rispettivamente, il secondo oggetto. Flex si prende cura dell'ordinamento attuale.

Questa funzione utilizza la stessa logica della funzione 'itemToLabel' per ottenere il valore nidificato appropriato. Quindi, in base al tipo di valore (che sia int, String o Date) lo confronta in modo appropriato e restituisce -1 se 'currentData1' è maggiore di 'currentData2', 0 se sono uguali e 1 se 'currentData2 'è maggiore di' currentData1 '.

Passaggio 13: collegamento della funzione di ordinamento personalizzata

Se hai notato, "customSortCompareFunction" non è una funzione predefinita nella classe DataGridColumn che sovrascriviamo. Questa funzione deve essere assegnata come funzione di ordinamento in un modo diverso. Dobbiamo assegnare alla variabile predefinita 'sortCompareFunction' il nome della funzione di ordinamento, che è 'customSortCompareFunction' nel nostro caso. Questo dovrebbe essere fatto all'interno del costruttore. Il costruttore ora si presenta così:

 funzione pubblica NestedDataGridColumn (columnName: String = null) // la funzione di ordinamento personalizzata assegnata alla variabile predefinita sortCompareFunction = mySortCompareFunction; super (columnName); 

Una volta fatto, sei pronto. Ora hai una classe personalizzata in grado di gestire dati nidificati arbitrariamente da mostrare in un DataGrid. E puoi ordinare la griglia come vuoi.

Conclusione

Oggi hai imparato come aggirare una limitazione della classe FlexDataGrid per ottenere dati annidati arbitrariamente e mostrarli in un DataGrid. Hai anche imparato a definire la tua funzione di ordinamento in modo che la griglia rimanga ordinabile. Ora puoi utilizzare questo NestedDataGridColumn in tutte le tue applicazioni senza sovraccarico.

È possibile estendere ulteriormente la funzione 'itemToLabel' per includere altri formati arbitrari di accesso, ad esempio l'accesso agli array all'interno degli oggetti figlio o l'accesso agli attributi xml. È inoltre possibile estendere ulteriormente la funzione di ordinamento per ordinare altri tipi di dati. Potresti anche essere in grado di aggiungere altre funzionalità come colorare le righe in base alla priorità della riunione e mostrare più dettagli sul relatore facendo clic su una riga.

Grazie per aver letto :)