Il presente articolo è stato tradotto automaticamente.

JavaScript

Associazione dati in un'applicazione Windows Store con JavaScript

Chris vende
Brandon Satrom

Scarica il codice di esempio

In questo articolo esploreremo l'associazione dati in un app Store Windows costruito con JavaScript.Si tratta di un ibrido di altri tipi di applicazioni per Windows 8.È come un'applicazione desktop che è installato sul tuo computer, a differenza di un sito Web.D'altra parte, è come un sito Web che si può costruire utilizzando HTML5, JavaScript e CSS3.Comunque, anziché generare l'interfaccia utente sul lato server, il framework JavaScript per la creazione di applicazioni Windows Store e il Runtime di Windows sottostante permette di creare applicazioni con stato sul lato client, archiviazione non in linea, controlli, modelli e associazione — insieme a tutta una serie di altri servizi.

Associazione dati è la possibilità di prendere il valore di un elenco di dati, ad esempio un insieme di feed RSS e usarlo per popolare un controllo, ad esempio un controllo ListView.Noi possiamo personalizzare dati che estraiamo utilizzando modelli.Vi mostreremo come associazione è ancora più flessibile di quello, che permette l'aggiornamento dell'interfaccia utente, come le modifiche ai dati sottostanti, insieme con l'ordinamento, il filtraggio e raggruppamento.

Quando si utilizza l'associazione dati, è spesso nel contesto di un controllo.Stiamo andando a dare un'occhiata al controllo ListView e il supporto per l'associazione dati e modelli.

101 Di associazione dati

L'utilizzo dell'associazione consente di impostare un'associazione tra due proprietà su due oggetti, spesso associando la proprietà di un oggetto con una proprietà di un elemento HTML Document Object Model (DOM), come Figura 1 illustrato.

Binding Between an Attribute on a Destination Element and a Property from a Source ObjectFigure 1 associazione tra un attributo su un elemento di destinazione e una proprietà da un oggetto di origine

Lo scopo di stabilire un'associazione è quello di copiare i dati tra i due oggetti coinvolti: la fonte da dove deriva i dati e la destinazione a cui i dati si va.Si potrebbe pensare che si può raggiungere questo obiettivo utilizzando un'istruzione di assegnazione:

 

myDestElem.value = mySourceObj.
name;

Fondamentalmente, l'assegnazione è quale associazione fa. Tuttavia, associazione non è solo una descrizione di quali dati di copia e dove, ma anche quando. "Quando" di un'associazione è generalmente uno dei seguenti:

  • Associazione unidirezionale: Copiare i dati per l'elemento DOM quando l'oggetto viene modificato. Questa è l'impostazione predefinita in Windows Library per JavaScript (WinJS).
  • Associazione una tantum: Copiare i dati per l'elemento DOM quando l'associazione viene stabilito prima. Questo è l'equivalente di assegnazione.
  • Associazione bidirezionale: Copiare i dati all'elemento DOM quando cambia l'oggetto e i dati all'oggetto quando cambia l'elemento DOM. Questo non è supportato in WinJS.

Per impostazione predefinita, WinJS associazione è associazione unidirezionale, anche se una tantum associazione è supportata anche. Anche se WinJS non supporta l'associazione bidirezionale, c'è un bel posto per agganciare il tuo motore preferito associazione bidirezionale, come quello di jQuery, come si vedrà.

Associazione di oggetti

Per iniziare, diciamo che vogliamo costruire un piccolo browser per le persone nella nostra vita, come mostrato Figura 2.

Figura 2 l'associazione di un oggetto a un insieme di elementi HTML

L'idea è che possiamo avere un numero di persone attraverso il quale noi possiamo navigare, ognuna con un nome, età e un colore preferito. Come si usa i pulsanti precedenti e successivi, abbiamo passare ad altre persone in lista, e se si preme il pulsante in mezzo — l'orologio — celebrare un compleanno aumentando l'età della persona attualmente visualizzata. Il seguente rappresenta l'insieme delle persone che ci avrai navigando nel nostro campione:

var people = [
  { name: "John", age: 18, favoriteColor: "red" },
  { name: "Tom", age: 16, favoriteColor: "green" },
  { name: "Chris", age: 42, favoriteColor: "blue" },
];

A partire da un modello di progetto applicazione di navigazione in Visual Studio 2012 fornisce HTML per poter inserire, come mostrato Figura 3.

Figura 3 il modulo principale

    <!DOCTYPE html>
    <!-- homePage.html -->
    <html>
    <head>
      <meta charset="utf-8" />
      <title>homePage</title>
      <!-- WinJS references -->
      <link href="//Microsoft.WinJS.1.0/css/ui-light.css" rel="stylesheet" />
      <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
      <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>
      <link href="/css/default.css" rel="stylesheet" />
      <link href="/pages/home/home.css" rel="stylesheet" />
      <script src="/pages/home/home.js"></script>
    </head>
    <body>
      <!-- The content that will be loaded and displayed.</span>
              <span class="sentence">-->
      <div class="fragment homepage">
        <header aria-label="Header content" role="banner">
          <button class="win-backbutton" aria-label="Back"
            disabled type="button"></button>
          <h1 class="titlearea win-type-ellipsis">
            <span class="pagetitle">Welcome to PeopleBrowser!</span>
          </h1>
        </header>
        <section aria-label="Main content" role="main">
          <!-- display each person -->
          <div id="nameLabel">Name</div>
          <input id="name" readonly="true" type="text" 
            data-win-bind="value: name" />
          <div id="ageLabel">Age</div>
          <input id="age" readonly="true" type="text" 
            data-win-bind="value: age" />
          <div id="colorLabel">Favorite Color</div>
          <div id="color" data-win-bind="style.backgroundColor:
            favoriteColor"></div>
          <div id="buttons">
            <button id="previousButton"></button>
            <button id="birthdayButton"></button>
            <button id="nextButton"></button>
          </div>
        </section>
      </div>
    </body>
    </html>

La parte interessante di questo HTML è l'uso dell'attributo associare-win, che utilizza il seguente formato:

    <div data-win-bind="destProp1: sourceProp1; destProp2: sourceProp2;..."></div>

La sintassi di associare-win è un elenco delimitato da punto e virgola di associazione di espressioni. Ogni espressione è la combinazione di una destinazione Proprietà elemento DOM e una proprietà di oggetto di origine. La sintassi punteggiata che stiamo usando per impostare il colore di sfondo sullo stile per il div del colore preferito, che è style.backgroundColor—works per proprietà sia l'origine e la destinazione e Trapani in suboggetti, come ci aspetterebbe.

Ogni proprietà di destinazione in un'espressione di associazione viene risolto contro l'elemento HTML che contiene l'attributo associare-vittoria. La domanda è: L'oggetto da dove proviene contro cui vengono risolti i nomi delle proprietà? La risposta è: il contesto dati.

Impostare il contesto dati è parte dell'operazione di associazione, che stabilisce l'associazione tra l'elemento HTML e qualsiasi oggetto viene utilizzato come contesto dati, come illustrato nel Figura 4.

Figura 4 impostare il contesto dati

// homePage.js
(function () {
  "use strict";
  WinJS.UI.Pages.define("/pages/home/home.html", {
    ready: function (element, options) {
      var people = [
        { name: "John", age: 18, favoriteColor: "red" },
        { name: "Tom", age: 16, favoriteColor: "green" },
        { name: "Chris", age: 42, favoriteColor: "blue" },
      ];
      // Bind the current person to the HTML elements in the section
      var section = element.querySelector("section[role=main]");
      var current = 0;
      WinJS.Binding.processAll(section, people[current]);
    }
  });
})();

La funzione di processAll nello spazio dei nomi WinJS.Binding è la funzione che analizza il vittoria associare attributi per una determinata gerarchia di elementi HTML, la sezione contenente gli elementi input e div nel nostro campione. La chiamata a processAll stabilisce le associazioni tra gli elementi HTML e il contesto dei dati come descritto in ogni attributo di associare-vittoria. Il contesto dati è il secondo argomento processAll e viene utilizzato per risolvere i nomi di proprietà trovati in ogni espressione di associazione. I risultati sembrano già cosa siamo dopo, come mostrato Figura 2.

Per impostazione predefinita, se non facciamo niente, abbiamo stabilito una connessione unidirezionale associazione tra l'oggetto contesto dati e l'elemento DOM. Ciò significa che come proprietà la modifica dell'oggetto origine dati, ci aspettiamo che l'output di cambiare così, come mostrato in Figura 5.

Figura 5 come proprietà la modifica dell'origine dei dati, così fa l'Output

function ready(element, options) {
  var people = [
    { name: "John", age: 18, favoriteColor: "red" },
    { name: "Tom", age: 16, favoriteColor: "green" },
    { name: "Chris", age: 42, favoriteColor: "blue" },
  ];
  var section = element.querySelector("section[role=main]");
  var current = 0;
  WinJS.Binding.processAll(section, people[current]);
  birthdayButton.onclick = function () {
    var person = people[current];
    person.age++; // Changing a bound property doesn't work yet ...
  };
}

L'implementazione del gestore click per il pulsante di compleanno cerca l'elemento corrente e modificata una proprietà, in particolare l'età. Tuttavia, non siamo abbastanza dove dobbiamo essere per ottenere l'interfaccia utente di aggiornare automaticamente.

Il problema è che un oggetto JavaScript standard non supporta qualsiasi protocollo di comunicazione per informare gli interessati, ad esempio l'associazione — che ha cambiato i dati. Per aggiungere la notifica protocollo è una questione di chiamare il metodo WinJS.Binding dello spazio dei nomi, come mostrato Figura 6.

Figura 6 l'aggiunta del protocollo di notifica

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    var current = 0;
    WinJS.Binding.processAll(section, people[current]);
    birthdayButton.onclick = function () {
      var person = people[current];
      person.age++; // Now this works!
    };
  }
});

Il metodo di "come" avvolge ogni oggetto, che fornisce il protocollo di notifica associazione così ogni modifica della proprietà notifica eventuali listener di associazione (ad esempio i nostri associati elementi HTML). Con questo codice, cambiando l'età di una persona è riflessa nell'interfaccia utente, come Figura 7 illustrato.

Changing the Underlying Data Automatically Updates the Bound HTML Elements
Figura 7 modifica automaticamente i dati sottostanti aggiorna gli elementi HTML associato

Abbiamo Associazione oggetto della singola persona all'insieme di elementi HTML per la visualizzazione, ma è possibile elaborare le espressioni di associazione dati in win associare attributi con un diverso tipo di contesto dati, come illustrato nel Figura 8.

Figura 8 le espressioni di associazione dati di elaborazione

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    var current = 0;
    var viewModel = WinJS.Binding.as({ person: people[current] });
    WinJS.Binding.processAll(section, viewModel);
    birthdayButton.onclick = function () {
      viewModel.person.age++;
    };
    // Bind to the previous object
    previousButton.onclick = function () {
      current = (people.length + current - 1) % people.length;
      viewModel.person = people[current];
    };
    // Bind to the next object
    nextButton.onclick = function () {
      current = (people.length + current + 1) % people.length;
      viewModel.person = people[current];
    };
  }
});

Qui è dove facciamo un cambiamento tra il passaggio di un singolo pezzo di dati dal "modello" di nostro app (cioè l'insieme dei dati che non ha nulla a che fare con la visualizzazione della stessa) di raggruppamento dei dati che sono appropriati per il nostro "vista" del modello (in questo caso, la persona a visualizzare corrente). Noi chiamiamo questa variabile il modello di"visualizzazione" dopo una tecnica famosa e utile per l'implementazione di interfacce utente chiamate Model-View-ViewModel (MVVM). Una volta che abbiamo costruito il nostro modello di visualizzazione come oggetto associabile, come la proprietà sottostante cambia (la persona, nel nostro caso) la vista è aggiornata. Abbiamo quindi associare la nostra vista al modello vista così che nel nostro avanti e indietro il pulsante gestori — come cambiare quale persona vorremmo Mostra — la vista viene notificata. Per questo lavoro, sarà necessario aggiornare il codice HTML per utilizzare il modello di visualizzazione invece la persona direttamente, come mostrato Figura 9.

Figura 9 aggiornamento HTML per utilizzare il modello di visualizzazione

 

    <section aria-label="Main content" role="main">
      <!-- display each person -->
      <div id="nameLabel">Name</div>
      <input id="name" readonly="true" type="text" 
        data-win-bind="value: person.name" />
      <div id="ageLabel">Age</div>
      <input id="age" readonly="true" type="text" 
        data-win-bind="value: person.age" />
      <div id="colorLabel">Favorite Color</div>
      <div id="color" 
        data-win-bind="style.backgroundColor: person.favoriteColor"></div>
      <div id="buttons">
        <button id="previousButton"></button>
        <button id="birthdayButton"></button>
        <button id="nextButton"></button>
      </div>
    </section>

Nella Figura 10 è illustrata la visualizzazione risultante.

You Can Rebind Different Objects to the Same Set of HTML Elements
Figura 10 è possibile riassociare oggetti diversi per lo stesso insieme di elementi HTML

Oltre agli elementi di associazione di oggetti, associazione consente di ascoltare semplicemente per un valore di cambiare. Ad esempio, adesso come si cambia l'indice al valore corrente quando l'utente preme i pulsanti precedenti o successivi, abbiamo ricordarsi di scrivere il codice per modificare campo di persona del modello visualizzazione per abbinare. Tuttavia, è possibile utilizzare associazione per aiutare qui, come mostrato Figura 11.

Figura 11 associazione di espressioni di ritrattamento

WinJS.UI.Pages.define("/pages/home/home.html", {
  ready: function (element, options) {
    var people = [
      // Notify binding listeners when these objects change
      WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
      WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
      WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
    ];
    // Bind the current person to the HTML elements in the section
    var section = element.querySelector("section[role=main]");
    // Listen for the current index to change and update the HTML
    var viewModel = WinJS.Binding.as({ current: 0, person: null });
    WinJS.Binding.processAll(section, viewModel);
    viewModel.bind("current", function (newValue, oldValue) {
      viewModel.person = people[newValue];
    });
    birthdayButton.onclick = function () {
      viewModel.person.age++;
    };
    // Bind to the previous object
    previousButton.onclick = function () {
      // Set the current index and let the binding do the work
      viewModel.current = (people.length + 
        viewModel.current - 1) % people.length;
    };
    // Bind to the next object
    nextButton.onclick = function () {
      // Set the current index and let the binding do the work
      viewModel.current = (people.length + 
        viewModel.current + 1) % people.length;
    };
  }
});

Invece di una semplice variabile per contenere l'indice alla persona attualmente visualizzata, aggiungiamo l'indice alla persona attualmente vista al nostro modello di vista associabile. Tutti gli oggetti associabili sono un metodo bind, che permette di ascoltare le modifiche alle proprietà dell'oggetto (la proprietà current in questo esempio). Quando l'utente fa clic sui pulsanti precedenti o successivi, abbiamo semplicemente modificare l'indice della persona di essere mostrato e lasciare che il processo del gestore di associazione corrente vittoria associare attributi per il codice HTML che mostra la persona attuale.

Se si desidera interrompere l'ascolto per associare gli eventi, è possibile chiamare il metodo di separazione.

Ora, come abbiamo accennato, tutto quello che hai visto funziona contro l'impostazione predefinita: associazione unidirezionale. Tuttavia, se si desidera impostare altri tipi di associazione o partecipare nel processo di associazione, si può farlo con un inizializzatore di associazione.

Inizializzatori di

Un inizializzatore è il terzo parametro opzionale per un'espressione di associazione che specifica una funzione da chiamare quando viene stabilita l'associazione:

    <div data-win-bind="destProp: sourceProp init" ...></div>

Fornisci un inizializzatore come parte di un'espressione di associazione, se volete partecipare o addirittura sostituire l'attuale comportamento di associazione — ad esempio, per eseguire una conversione di dati o persino collegare jQuery associazione bidirezionale. Un inizializzatore di associazione è una funzione che assume per l'associazione unidirezionale predefinita e ha la seguente firma:

function myInit(source, sourceProperties,   dest, destProperties) {...}

I dettagli di implementazione di un inizializzatore personalizzato sono oltre la portata di questo articolo, ma WinJS ha diversi inizializzatori incorporati che possono trarre vantaggio. Ad esempio, se desiderate fare una tantum invece associazione unidirezionale, è possibile utilizzare la funzione oneTime dallo spazio dei nomi WinJS.Binding:

    <input data-win-bind=   "value: person.
    name WinJS.Binding.oneTime"></input>

A altra estremità dello spettro, quando si esegue l'associazione unidirezionale, è spesso utile eseguire la conversione di dati (anche noto come trasformazione dei dati). Si supponga, ad esempio, che abbiamo voluto precisare l'età delle persone nella nostra vita:

function getWordsFromNumber(i) {...}
// Convert ages to words
window.ageToWords =
  WinJS.Binding.converter(function (value) { 
    return getWordsFromNumber(value); 
  });

La funzione di convertitore nello spazio dei nomi WinJS.Binding fornisce la parte dura dell'implementazione inizializzatore; tutto quello che dovete fare è fornire una funzione per eseguire la conversione effettiva e verrà chiamato come i cambiamenti di valore di origine. Utilizzo in HTML sembra che ci si aspetta:

    <input data-win-bind="value: person.age ageToWords"></input>

Potete vedere i risultati in Figura12.

Translating a Numeric Age into Words via Data Conversion
Figura 12 tradurre un'età numerica parole tramite la conversione di dati

Associazione valori uno alla volta è utile, ma ancora più utile, soprattutto per le applicazioni Windows Store — è vincolante insiemi di valori in una sola volta. Per questo abbiamo l'elenco dell'associazione.

Un elenco di associazione

Immaginate un semplice esempio di utilizzo di un controllo ListView con un insieme di valori:

<div data-win-control="WinJS.UI.ListView"
  data-win-options="{itemDataSource: items.dataSource}">
</div>

Qui stiamo creando un controllo ListView in modo dichiarativo HTML associato alla proprietà dataSource di un oggetto elementi globali. Nel nostro JavaScript, è facile creare e compilare l'oggetto elementi come un elenco di associazione:

// A global binding list of items
window.items = new WinJS.Binding.List();
[0, 1, 2].forEach(function (i) {
  WinJS.Promise.timeout(500 * (i+1)).done(function () {
    // Add an item to the binding list, updating the ListView
    items.push(i);
  });
});

In questo codice creiamo una lista di associazione (un'istanza del tipo di elenco dei nomi WinJS.Binding) e abbiamo un ciclo su un array di valori, utilizzando ciascuno per creare un timeout, che è una promessa che sarà il fuoco a un certo momento, in futuro, secondo l'argomento si passano (millisecondi). Al termine di ogni timeout, vedremo il controllo ListView ottenere un valore aggiunto, come Figura 13 illustrato.

The ListView Updating as the Underlying Binding List Updates
Figura 13 il ListView l'aggiornamento elenco sottostante associazione aggiorna

L'HTML non fornisce un ID per il controllo ListView, né JavaScript interagisce con il controllo ListView in alcun modo. Invece, il codice HTML e JavaScript entrambi rendezvous sugli elementi di associazione di elenco. È la lista di associazione che implementa la collezione associazione API (chiamato IListDataSource). Anziché far si programma direttamente contro IListDataSource — non è particolarmente programmatore-friendly — elenco associazione espone la sua attuazione IListDataSource tramite la proprietà dataSource.

Per fornire una API che è più familiare possibile a programmatori JavaScript, elenco associazione implementa un API simile e semantica simile come matrice incorporata supporta, ad esempio, spingere, pop, tagliare, giuntare e così via. Come un confronto, ecco come funziona la matrice JavaScript incorporata:

// Using the built-in array
var array = [];
array.push("one");
array.push("two");
array.push("three");
var x = array[0]; // x = "one"
var y = array[1]; // y = "two"
array[2] = "THREE";
var z = array[2]; // z = "THREE";

La lista di associazione si comporta allo stesso modo tranne che invece di utilizzare un indicizzatore — cioè, quadre — espone oggetti via setAt e getAt:

// Using the WinJS binding list
var list = new WinJS.Binding.List();
list.push("one");
list.push("two");
list.push("three");
var x = list.getAt(0); // x = "one"
var y = list.getAt(1); // y = "two"
list.setAt(2, "THREE");
var z = list.getAt(2); // z = "THREE";

Ordinamento e filtro

API familiare, la lista dell'associazione è stata costruita con app Store Windows costruzione esigenze in mente. Hai già visto come la proprietà dataSource consente di collegare al controllo ListView. Inoltre, potrebbe essere interessato a ordinamento e filtro dei dati. Ad esempio, ecco la lista delle persone di nuovo, questa volta avvolto in un elenco di associazione:

var people = new WinJS.Binding.List([
  { name: "Tom", age: 16 },
  { name: "John", age: 17 },
  { name: "Chris", age: 42 },
]);
// Sort by name
window.sortedPeople = people.createSorted(function (lhs, rhs) { 
    return lhs.name.localeCompare(rhs.name); 
  });
// Filter by age (adults only)
window.filteredPeople = people. 
  createFiltered(function (p) { return p.age > 17; });

Possiamo ordinare un elenco di associazione chiamando il metodo createSorted, passando in una funzione di ordinamento o filtro chiamando il metodo createFiltered, passando in una funzione di filtraggio. Il risultato di una chiamata di queste creare metodi è una visualizzazione dei dati che si guarda e si comporta come un'altra istanza dell'associazione elenco, e noi possiamo associare a un controllo ListView, come Figura 14 illustrato.

Filtering a Binding List
Figura 14 filtrare un elenco di associazione

Invece di fornire una copia dei dati sottostanti, i metodi createSorted e createFiltered restituiscono una vista diretta sui dati esistenti. Ciò significa che eventuali modifiche ai dati sottostanti vengono riflesse nelle viste e verranno mostrate in eventuali controlli associati. Ad esempio, noi potremmo aggiungere un minore all'elenco sottostante:

// Changes to the underlying data are reflected in the live views
var person = { name: "Pete", age: 17, favoriteColor: "black" };
people.push(person);

Anche se stiamo cambiando i dati sottostanti, verrà aggiornata la visualizzazione ordinata e ListView verrà notificato del cambiamento, come Figura 15 illustrato.

Sorting a Binding List
Figura 15 un elenco vincolante

Inoltre, perché la vista da metodi create Guarda e si sente come un elenco di associazione, si ulteriormente ordinare o filtrare la visualizzazione in modo sovrapposte:

// Filterd by age (minors) and sorted by name
window.filteredSortedPeople = people. 
  createFiltered(function (p) { return p.age < 18; }).
  createSorted(function (lhs, rhs) { 
    return lhs.name.localeCompare(rhs.name); 
  });

I risultati dell'associazione alla visualizzazione filtrata e ordinata risulta non dovrebbero essere una sorpresa (vedere Figura 16).

Sorting and Filtering a Binding List
Figura 16 ordinamento e filtro di un elenco di associazione

Prestare attenzione quando si impilano farlo nell'ordine corretto. Nel caso di filtraggio, se ordinare o raggruppare prima e poi filtrare, si sta facendo più lavoro di quanto è necessario. Inoltre, ogni livello vista è sopra la testa, quindi ti consigliamo di assicurarsi che voi stack loro solo profonda come necessario.

Raggruppamento

Oltre a ordinamento e filtro dei dati elenco associazione, è anche possibile raggruppare e da alcuni criteri dei dati. Ad esempio, adulti e minori avrebbero funzionato bene per i nostri dati di esempio:

// Group by age
window.groupedPeople = people. 
  createGrouped(function (p) { 
    return p.age < 18 ? "minor" : "adult"
  });

Il valore restituito della funzione di raggruppamento è un valore stringa che identifica in modo univoco il gruppo, nel nostro caso, la stringa "minore" o la stringa "adulto". Associazione per la visualizzazione dei dati raggruppata Mostra i dati organizzati dal gruppo — che è, tutti gli elementi di ciascun gruppo prima di passare al gruppo successivo, come Figura 17 illustrato.

Grouping a Binding List
17 Figura un elenco vincolante di raggruppamento

Questo esempio mostra due gruppi, ma si può avere qualsiasi numero di gruppi. Inoltre, proprio come createSorted e createFiltered, il metodo createGrouped restituisce una visualizzazione diretta dei dati, quindi le modifiche nei dati sottostanti verranno riflesse nelle destinazioni di associazione.

Tuttavia, mentre è chiaro a noi, gli sviluppatori, che noi stiamo ordinamento i gruppi — prima adulti e poi minori — non è chiaro agli utenti del nostro programma perché non non c'è nessun indicatore visivo del raggruppamento. Per chiedere il controllo ListView per fornire un indicatore visivo di raggruppamento, il controllo ListView consente di specificare due insiemi di dati: l'elenco di elementi raggruppati e i gruppi stessi. Configurare il controllo ListView con entrambi i set di dati assomiglia a questo:

    <div data-win-control="WinJS.UI.ListView"
      data-win-options="{itemDataSource: groupedPeople.dataSource,
         groupDataSource: groupedPeople.groups.dataSource}">
    </div>

Una volta abbiamo creato la vista raggruppata l'elenco dell'associazione, la proprietà di gruppi espone un elenco di quei gruppi così li possono utilizzare il controllo ListView. Tuttavia, prima possiamo farlo funzionare, abbiamo anche bisogno di tornare al nostro utilizzo della funzione createGrouped:

// Group by age
function groupKeySelector(p) { return p.age < 18 ? "minor" : "adult"; };
function groupDataSelector(p) { return p.age < 18 ? "minor" : "adult"; };
window.groupedPeople = people.createGrouped(groupKeySelector, groupDataSelector);

In precedenza, quando noi stavamo raggruppamento, abbiamo solo bisogno di fornire una funzione che potrebbe fare il raggruppamento basato su qualche identificatore unico gruppo. Tuttavia, se vogliamo visualizzare i gruppi per l'utente, abbiamo bisogno di un altro metodo che può estrarre i gruppi stessi (se si voleva scegliere l'ordine dei gruppi, è possibile fornire un terzo metodo per il metodo createGroup che fa l'ordinamento). In entrambi i casi, stiamo fornendo una stringa per rappresentare il gruppo anche per compilare l'elenco dei gruppi, che funziona bene, come si può vedere in Figura 18.

Grouping a Binding List with ListView Headers
Figura 18 raggruppamento un elenco vincolante con ListView Headers

Come Figura 18 spettacoli, il gruppo è effettivamente utilizzato per decorare i dati raggruppati, rendendo molto facile vedere quali dati cade in quale gruppo. Purtroppo, anche con questa indicazione visiva di raggruppamento, nostri oggetti formato JSON non sono realmente UI vogliamo mostrare i nostri utenti. Per questo lavoro il modo che vogliamo richiede modelli.

Modelli

Un modello è una radicata singolo gerarchia di elementi HTML con optional "buchi" da riempire di dati dinamici. L'attributo vittoria associare il div definisce i fori utilizzando win associare attributi. Ad esempio, potremmo creare un modello per la nostra persona oggetti in questo modo:

    <div id="itemTemplate" data-win-control="WinJS.Binding.Template">
      <span data-win-bind="style.color: favoriteColor">
        <span data-win-bind="textContent: name"></span>
        <span> is </span>
        <span data-win-bind="textContent: age"></span>
        <span> years old</span>
      </span>
    </div>

Ciò che rende questo pezzo di HTML un modello è l'attributo win-controllo dei dati, imposta il tipo di controllo WinJS.Binding.Template. Una volta che abbiamo il nostro modello, è necessario renderlo per riempire i fori con i dati:

// Manual template rendering
var person = { name: "Pete", age: 17, favoriteColor: "black" };
var template = itemTemplate.winControl;
template.render(person).done(function (element) {
  peteDiv.appendChild(element);
});

Perché il modello è solo un altro controllo (anche se un controllo che nasconde se stessa fino a visualizzare manualmente), possiamo raggiungere in div che lo definisce e ottenere l'accesso alla sua funzionalità tramite una proprietà ben nota chiamato winControl. La funzionalità che si desidera accedere è il metodo render del modello, che utilizza un contesto dati da utilizzare in associazione il vittoria associare attributi e produce un elemento HTML completamente formato per noi di fare quello che vogliamo con.

Se il controllo ListView fornisce un modello, renderà ogni elemento nel controllo ListView con quel modello. Infatti, il controllo ListView può avere modelli per riprodurre le intestazioni di gruppo e di elementi. Per vedere che in azione, prima aggiorniamo i gruppi di oggetti, più tipico:

// Fancy group by age
var groups = [{ key: 1, name: "Minor" }, { key: 2, name: "Adult" }];
function groupDataSelector(p) { 
  return p.age < 18 ? groups[0] : groups[1]; 
};
function groupKeySelector(p) { return groupDataSelector(p).key; };
window.fancyGroupedPeople = 
  people.createGrouped(groupKeySelector, groupDataSelector);

In questo codice, abbiamo due oggetti gruppo, ciascuno con una chiave e un nome, e abbiamo ottenuto dati separati e funzioni di selettore a chiave che restituiscono il gruppo stesso o chiave del gruppo, rispettivamente. Con i nostri dati gruppo reso un po' più reale-mondo-come, viene creato un modello per l'intestazione di gruppo, come mostrato Figura 19.

Figura 19 modello per l'intestazione di gruppo

    <div id="headerTemplate" data-win-control="WinJS.Binding.Template">
      <span data-win-bind="textContent: name"></span>
    </div>
    <div id="itemTemplate" data-win-control="WinJS.Binding.Template">
      <span data-win-bind="style.color: favoriteColor">
        <span data-win-bind="textContent: name"></span>
        <span> is </span>
        <span data-win-bind="textContent: age"></span>
        <span> years old</span>
      </span>
    </div>
    <h1>Fancy Grouped</h1>
    <div data-win-control="WinJS.UI.ListView"
      data-win-options="{
        groupDataSource: fancyGroupedPeople.groups.dataSource,
        groupHeaderTemplate: select('#headerTemplate'),
        itemDataSource: fancyGroupedPeople.dataSource,
        itemTemplate: select('#itemTemplate')}">
    </div>

Il modello per l'intestazione di gruppo viene creato come un modello di elemento. I modelli di intestazione e voce del gruppo vengono passati al controllo ListView mediante le proprietà groupHeaderTemplate e itemTemplate nell'attributo dati-opzioni di vittoria. Nostro amatore raggruppati dati sembra che Figura 20.

Grouping a Binding List with ListView Headers and Templates
Figura 20 raggruppare un elenco vincolante con ListView Headers e modelli

OK, ammettiamo che non è molto di fantasia, ma la combinazione di gruppi e oggetti, inclusi i modelli, mostra la potenza dell'elenco vincolante. Infatti, la lista dell'associazione è così utile, è il nucleo del modello asincrono dei dati esposto dal file data.js generato dalla griglia e Split applicazione modelli di progetto, come illustrato nel Figura 21.

Figura 21 il File Data.js generato dall'applicazione della griglia e progetto applicazione Split

// data.js
(function () {
  "use strict";
  var list = new WinJS.Binding.List();
  var groupedItems = list.createGrouped(
      function groupKeySelector(item) { return item.group.key; },
      function groupDataSelector(item) { return item.group; }
  );
  // TODO: Replace the data with your real data.
  // You can add data from asynchronous sources whenever it becomes available.</span>
  generateSampleData().forEach(function (item) {
    list.push(item);
  });
  WinJS.Namespace.define("Data", {
    items: groupedItems,
    groups: groupedItems.groups,
    getItemsFromGroup: getItemsFromGroup,
    ...
  });
  ...
  // This function returns a WinJS.Binding.List containing only the items
  // that belong to the provided group.
  function getItemsFromGroup(group) {
    return list.createFiltered(function (item) {
    return item.group.key === group.key; });
  }
  ...
 });
})();

Si può vedere la creazione di un elenco vuoto di associazione, la creazione di una versione raggruppata di tale elenco funzioni chiave e selezione dei dati tramite i gruppi, un piccolo ciclo forEach che aggiunge che elementi all'elenco vincolante e, infine, un supporto funzionano che fa filtro.

Dove siamo?

Abbiamo iniziato questo articolo da scavare in associazione, la possibilità di associare una proprietà di un oggetto a un attributo in un elemento HTML. Fuori dalla scatola, WinJS supporta gli inizializzatori di associazione unidirezionale, unica e personalizzata, ma l'associazione non bidirezionale. Associazione è supportata su singoli oggetti associabili, nonché gli elenchi di oggetti che implementano l'interfaccia IListDataSource. Il posto più facile per ottenere un'implementazione dell'interfaccia IListDataSource è tramite l'oggetto elenco (WinJS.Binding.List) associazione che supporta pienamente l'ordinamento, il filtraggio e raggruppamento. Abbiamo anche visto come modelli utili sono quando combinato con l'associazione e quanto utile sia l'associazione di modelli sono quando si tratta di controlli che supportano l'associazione di elenco, ad esempio il controllo ListView.

Chris Sells è il vice presidente della divisione Developer Tools di Telerik. È coautore di "Building Windows 8 Apps con JavaScript" (Addison-Wesley Professional, 2012), da cui questo articolo è stato adattato. Ulteriori informazioni sulle vendite e i suoi vari progetti, sono disponibile a sellsbrothers.com.

Brandon Satrom è un program manager nella divisione Kendo UI di Telerik. È coautore di "Building Windows 8 Apps con JavaScript" (Addison-Wesley Professional, 2012), da cui questo articolo è stato adattato. È possibile seguirlo su Twitter a twitter.com/BrandonSatrom.

Grazie ai seguenti esperti tecnici per la revisione di questo articolo: Chris Anderson, Jonathan Antoine, Michael Weinhardt, Shawn Wildermuth e Josh Williams