Compartir a través de


Este artículo proviene de un motor de traducción automática.

JavaScript

Enlace de datos en una aplicación para la Tienda Windows con JavaScript

Chris Sells
Brandon Satrom

Descargar el ejemplo de código

En este artículo veremos el enlace de datos en una aplicación de Windows tienda construida con JavaScript.Se trata de un híbrido de otros tipos de aplicaciones para Windows 8.Es como una aplicación de escritorio que se instala en su ordenador, a diferencia de un sitio Web.Por otro lado, es como un sitio Web en que se puede construir utilizando JavaScript, HTML5 y CSS3.Sin embargo, en lugar de generar la interfaz de usuario en el servidor, el framework JavaScript para construir aplicaciones de la tienda de Windows y el tiempo de ejecución de Windows subyacente permite crear aplicaciones con estado de cliente, almacenarlos, controles, plantillas y vinculante — junto con un montón de otros servicios.

Enlace de datos es la capacidad de tomar el valor de una lista de datos, como un conjunto de canales RSS y utilizarlo para rellenar un control, como un control ListView.Podemos adaptar los datos extraemos utilizando plantillas.Le mostraremos cómo vinculante es aún más flexible, permitiendo la actualización de la interfaz de usuario como los cambios de datos subyacente, junto con la ordenación, filtrado y agrupación.

Cuando usamos el enlace de datos, es a menudo en el contexto de un control.Vamos a echar un vistazo en el ListView y su apoyo para el enlace de datos y plantillas.

101 El enlace de datos

El uso de enlace permite configurar una asociación entre dos propiedades en dos objetos, suele asociar la propiedad de un objeto con una propiedad en un elemento HTML Document Object Model (DOM), como figura 1 muestra.

Binding Between an Attribute on a Destination Element and a Property from a Source ObjectFigura 1 enlace entre un atributo de un elemento de destino y una propiedad de un objeto de origen

El propósito de establecer un enlace es copiar datos entre los dos objetos implicados: la fuente de procedencia de los datos y el destino al que se pasan los datos.Se piensa que puede lograr este objetivo mediante una instrucción de asignación simple:

myDestElem.value = mySourceObj.
name;

Fundamentalmente, asignación es enlace de lo que hace. Sin embargo, vinculante no es sólo una descripción de los datos para la copia y donde, sino también cuando. El "cuando" de un enlace es generalmente uno de los siguientes:

  • Enlace unidireccional: Copiar los datos en el elemento de DOM cuando cambia el objeto. Esta es la opción predeterminada en la biblioteca de Windows para JavaScript (WinJS).
  • Enlace de una sola vez: Copiar los datos en el elemento de DOM cuando primero se establece el enlace. Esto es el equivalente de asignación.
  • Enlace bidireccional: Copiar los datos en el elemento de DOM cuando el objeto cambia y copiar los datos en el objeto cuando cambia el elemento DOM. Esto no es compatible con WinJS.

De forma predeterminada, WinJS enlace es enlace unidireccional, aunque también se admite el enlace de una sola vez. Aunque WinJS no admite enlace bidireccional, hay un lugar agradable para enganchar en el motor de enlace bidireccional favoritos, como el de jQuery, como veremos.

Objetos de enlace

Para empezar, digamos que queremos construir un pequeño navegador para la gente en nuestras vidas, como se muestra en figura 2.

Figura 2 enlace de un objeto a un conjunto de elementos HTML

La idea es que podemos tener un número de personas a través del cual nos podemos navegar, cada uno con un nombre, edad y un color favorito. Como usamos los botones anteriores y siguientes, navegamos a otras personas en la lista, y si pulsamos el botón en el medio — el reloj — celebramos un cumpleaños por aumento de la edad de la persona que se muestra actualmente. La siguiente representa el conjunto de personas que va navegando en nuestra muestra:

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

A partir de una plantilla de proyecto de aplicación de navegación en 2012 de Visual Studio proporciona HTML para nosotros rellenar, como se muestra en figura 3.

Figura 3 el formulario principal

    <!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.
    -->
      <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 interesante de este HTML es el uso del atributo enlazar los datos-Victoria, que utiliza el siguiente formato:

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

La sintaxis de enlazar los datos-win es una lista delimitada por punto y coma de expresiones de enlace. Cada expresión es la combinación de un destino de propiedad de elemento DOM y una propiedad del objeto de origen. La sintaxis con puntos que estamos usando para establecer el color de fondo en el estilo de la div color favorito — es decir, style.backgroundColor—works propiedades de origen y el destino y se perfora en objetos secundarios, como era de esperar.

Cada propiedad de destino en una expresión de enlace se resuelve contra el elemento HTML que contiene el atributo de datos-win-bind. La pregunta es: ¿De dónde proviene el objeto contra el que se resuelven los nombres de propiedad? Y la respuesta es: el contexto de datos.

El contexto de datos es parte de la operación de enlace, que establece la asociación entre el elemento HTML y cualquier objeto sirve como el contexto de datos, como se muestra en figura 4.

Figura 4 el contexto de datos

// 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 función de processAll en el espacio de nombres de WinJS.Binding es la función que analiza los atributos de datos-win-bind para una determinada jerarquía de elementos HTML, la sección que contiene los elementos de entrada y div en nuestra muestra. La llamada a processAll establece los enlaces entre los elementos HTML y el contexto de datos como se describe en cada atributo de datos-win-bind. El contexto de datos es el segundo argumento processAll y se utiliza para resolver los nombres de propiedad que se encuentra en cada expresión de enlace. Los resultados parecen ya estamos después, como se muestra en figura 2.

De forma predeterminada, si no hacemos nada, hemos establecido una conexión de enlace unidireccional entre el objeto de contexto de datos y el elemento DOM. Esto significa que como propiedades en el cambio de objeto de origen de datos, esperamos que la salida para cambiar así, como se muestra en la figura 5.

Figura 5 como propiedades en el cambio de fuente de datos, también lo hace la salida

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 ...
};
}

Nuestra implementación del controlador haga clic en el botón de cumpleaños busca el elemento actual y cambia una propiedad, específicamente la edad. Sin embargo, no somos bastante donde necesitamos obtener la interfaz de usuario se actualizan automáticamente.

El problema es que un objeto de JavaScript estándar no soporta cualquier protocolo de notificación para informar a las partes interesadas — como un enlace, que ha cambiado sus datos. Para agregar la notificación protocolo trata de llamar al método del espacio de nombres WinJS.Binding, como se muestra en figura 6.

Figura 6 agregar el Protocolo de notificación

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!
};
  }
});

El método "como" envuelve cada objeto, proporcionar el Protocolo de notificación obligatoria para que cada cambio de propiedad notifica cualquier oyentes de enlace (como nuestros elementos HTML dependientes). Con este código en su lugar, cambiar la edad de una persona se refleja en la interfaz de usuario, como figura 7 muestra.

Changing the Underlying Data Automatically Updates the Bound HTML Elements
Figura 7 cambiar automáticamente los datos subyacentes se actualiza los elementos HTML dependiente

Hemos sido vinculante objeto de un sola persona al conjunto de elementos HTML para la visualización, pero puede procesar las expresiones de enlace de datos en los atributos de Victoria y enlazarse con otro tipo de contexto de datos, como se muestra en figura 8.

Figura 8 procesar las expresiones de enlace de datos

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];
    };
  }
});

Aquí es donde hacemos un cambio entre pasar en una sola pieza de datos de «modelo» de nuestra aplicación (es decir, el conjunto de datos que nada tiene que ver con la presentación de sí mismo) para agrupar los datos adecuados para nuestra "visión" de ese modelo (en este caso, la persona actual para ver). Que llamamos a esta variable el «modelo de vista» después de una famosa y útil técnica para la implementación de interfaces de usuario llamados modelo-View-ViewModel (MVVM). Una vez que hemos construido nuestro modelo de vista como un objeto enlazable, como las propiedades subyacentes cambiar (la persona, en nuestro caso) la vista se actualiza. Nos luego enlazar nuestro punto de vista para el modelo de vista, por lo que en nuestra siguiente y atrás botón controladores — cambiemos qué persona nos gustaría ver — se notifica a la vista. Para que funcione, necesitamos actualizar el código HTML para utilizar el modelo de vista en lugar de la persona directamente, como se muestra en figura 9.

Figura 9 Actualizar HTML para utilizar el modelo de vista

 

    <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>

Figura 10 muestra el resultado.

You Can Rebind Different Objects to the Same Set of HTML Elements
Figura 10 puede enlazar objetos diferentes para el mismo conjunto de elementos HTML

Además de enlazar objetos a elementos, enlace también permite escuchar simplemente para que un valor de cambio. Por ejemplo, ahora cambiemos el índice al valor actual cuando el usuario hace clic en los botones siguientes o anteriores, tenemos que recordar que escribir el código para cambiar el campo de persona del modelo de la vista para que coincida con. Sin embargo, usted podría utilizar vinculantes para ayudar aquí, como se muestra en figura 11.

Figura 11 reprocesamiento de expresiones de enlace

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;
    };
  }
});

En lugar de una variable simple que contenga el índice a la persona se muestra actualmente, agregamos el índice a la persona visualizada a nuestro modelo de vista enlazables. Todos los objetos enlazables tienen un método de bind, que nos permite escuchar para cambios en las propiedades del objeto (la propiedad actual en este ejemplo). Cuando el usuario hace clic en los botones siguientes o anteriores, simplemente cambiamos el índice de la persona actual que se muestra y el proceso del controlador de enlace los atributos de datos-win-bind para el código HTML que se muestra a la persona actual.

Si desea detener la escucha de eventos de enlace, puede llamar al método de desvinculación.

Ahora, como hemos mencionado, todo lo que has visto trabaja contra el valor por defecto: enlace unidireccional. Sin embargo, si desea configurar otro tipo de enlace o participar en el proceso de enlace, puede hacerlo con un inicializador de enlace.

Inicializadores

Un inicializador es el tercer parámetro opcional a una expresión de enlace que especifica una función para llamar cuando se establece el enlace:

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

Proporcionar un inicializador como parte de una expresión de enlace si desea participar en o incluso reemplazar el comportamiento de enlace existentes — por ejemplo, para realizar una conversión de datos o incluso conectar enlace bidireccional de jQuery. Un inicializador de enlace es una función que se apodera del enlace unidireccional predeterminado y tiene la firma siguiente:

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

Los detalles de la aplicación de un inicializador personalizado están fuera del alcance de este artículo, pero WinJS tiene varios inicializadores incorporados que puede aprovechar. Por ejemplo, si desea hacer una sola vez en lugar de enlace unidireccional, puede utilizar la función una vez fuera del espacio de nombres WinJS.Binding:

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

En el otro extremo del espectro, al realizar el enlace unidireccional, suele ser útil realizar la conversión de datos (también conocido como transformación de datos). Por ejemplo, imagine que queríamos deletrear las edades de las personas en nuestra vida:

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

La función del convertidor en el espacio de nombres WinJS.Binding proporciona la parte dura de la aplicación de inicializador; todo lo que tienes que hacer es proporcionar una función para realizar la conversión real y se llamará como los cambios de valor de la fuente. Utilizar en el código HTML parece que usted esperaría:

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

Puede ver los resultados en figura12.

Translating a Numeric Age into Words via Data Conversion
Figura 12 traducir palabras a través de la conversión de datos a una edad numérica

Enlace valores uno a la vez es útil, pero aún más útil — especialmente para aplicaciones de Windows Store — es vinculante colecciones de valores a la vez. Para eso tenemos la lista de enlace.

Una lista de enlace

Imaginar un ejemplo sencillo del uso de un control ListView con una colección de valores:

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

Aquí estamos creando un control ListView mediante declaración en HTML que se enlaza a la propiedad dataSource de un objeto de elementos globales. En nuestro JavaScript, es fácil crear y rellenar el objeto de elementos como una lista de enlace:

// 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);
  });
});

En este código creamos una lista de enlace (una instancia del tipo lista del espacio de nombres WinJS.Binding) y nos abrace con una matriz de valores, utilizando cada uno para crear un tiempo de espera, que es una promesa que se disparará en algún momento en el futuro, según el argumento que pase (en milisegundos). Una vez finalizada cada tiempo de espera, veremos el control ListView obtener un valor adicional, como figura 13 muestra.

The ListView Updating as the Underlying Binding List Updates
La actualización de ListView como la lista de enlace subyacente actualiza Figura 13

El código HTML no proporcione un ID para el control ListView, ni interactúa con el control ListView en modo alguno el JavaScript. Por el contrario, el código HTML y JavaScript tanto cita sobre los elementos vinculantes de la lista. Es la lista de enlace que implementa la colección enlace API (llamada IListDataSource). En lugar de hacer programa contra IListDataSource directamente — no es particularmente respetuoso con el medio programador — la lista enlace expone su aplicación IListDataSource a través de la propiedad dataSource.

Para proporcionar una API que es tan familiar como sea posible a los programadores de JavaScript, la lista de enlace implementa una API similar y semántica similar como la matriz incorporada soporta — por ejemplo, push, pop, cortar, empalmar y así sucesivamente. Como comparación, así es como funciona la matriz JavaScript incorporada:

// 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 de enlace se comporta de manera similar excepto que en lugar de utilizar un indizador — es decir, corchetes — expone artículos vía setAt y 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";

Ordenar y filtrar

Además de la API de familiar, la lista enlace fue construida con la app Store de Windows en cuenta necesidades de construcción. Ya hemos visto cómo la propiedad dataSource le permite conectar con el control ListView. Además, usted podría ser interesado en ordenar y filtrar los datos. Por ejemplo, aquí está nuestra lista de personas nuevamente, esta vez envuelto en una lista de enlace:

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; });

Podemos ordenar una lista de enlace llamando al método createSorted, pasa una función de clasificación, o filtro llamando al método createFiltered, pasando de una función de filtrado. El resultado de llamar a uno de estos métodos de crear es un punto de vista sobre los datos que se ve y actúa como otra instancia de la lista de enlace, y nosotros podemos enlazar a un control ListView, como figura 14 muestra.

Filtering a Binding List
Figura 14 filtrar una lista de enlace

En lugar de proporcionar una copia de los datos subyacentes, los métodos createSorted y createFiltered devuelven una vista en vivo sobre los datos existentes. Esto significa que cualquier cambio en los datos subyacentes se refleja en los puntos de vista y se mostrarán en cualquier control enlazado. Por ejemplo, podríamos añadir a un menor a la lista subyacente:

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

A pesar de que estamos cambiando los datos subyacentes, se actualizará la vista ordenada y ListView será notificado del cambio, como figura 15 muestra.

Sorting a Binding List
Figura 15 ordenar una lista de enlace

También, porque la vista de los métodos de crear se ve y se siente como una lista de enlace, además puede ordenar o filtrar la vista de forma apilada:

// 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); 
  });

Los resultados de enlace a la vista filtrada y ordenada resultante no deberían ser una sorpresa (ver figura 16).

Sorting and Filtering a Binding List
Figura 16 ordenar y filtrar una lista de enlace

Tenga cuidado al hacerlo en el orden correcto de apilamiento. En el caso de filtrado, si ordenar o agrupar primero y luego filtrar, estás haciendo trabajar más de lo necesario. Además, cada capa de la vista es aérea, así que usted querrá asegurarse de que usted apilarlos sólo tan profunda como sea necesario.

Agrupación

Además de ordenar y filtrar los datos de la lista de enlace, también se pueden agrupar por algunos criterios de los datos. Por ejemplo, adultos y menores funcionaría bien para nuestros datos de la muestra:

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

El valor devuelto por la función de agrupación es un valor de cadena que identifica el grupo — en nuestro caso, la cadena «menor» o la cadena "adulto". Enlace a la vista agrupada de los datos muestra los datos organizados por el grupo — es decir, todos los elementos de cada grupo antes de pasar en el próximo grupo, como figura 17 muestra.

Grouping a Binding List
17 Figura una lista de enlace de agrupación

Este ejemplo muestra dos grupos, pero puede tener cualquier número de grupos. También, al igual que createSorted y createFiltered, el método createGrouped devuelve una vista sobre datos en vivo, por lo que cambios en los datos subyacentes se reflejará en los destinos de bind.

Sin embargo, aunque es evidente para nosotros, los desarrolladores, que estamos clasificación los grupos — primero los adultos y los menores — no resulta claro para los usuarios de nuestro programa porque no hay ningún indicador visual de la agrupación. Para pedir el control ListView para proporcionar un indicador visual de la agrupación, el control ListView permite especificar dos conjuntos de datos: la lista de elementos agrupados y los propios grupos. Configurar ListView con ambos conjuntos de datos se ve así:

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

Una vez que hemos creado la vista agrupada de la lista de enlace, la propiedad de los grupos expone una lista de esos grupos para que ListView pueda utilizarlos. Sin embargo, antes de que nosotros podemos hacer que funcione, también tenemos que volver a nuestro uso de la función 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);

Anteriormente, cuando nos fuimos agrupando, sólo necesitábamos proporcionar una función que podría hacer la agrupación basada en algún identificador de grupo único. Sin embargo, si queremos realmente visualizar los grupos para el usuario, necesitamos otro método que puede extraer los mismos grupos (si desea elegir el orden de los grupos, podría proporcionar un tercer método al método createGroup que hace la clasificación). En ambos casos, estamos proporcionando una cadena para representar el grupo, así como para construir la lista de grupos, que funciona muy bien, como usted puede ver en figura 18.

Grouping a Binding List with ListView Headers
18 Figura una lista de enlace con ListView encabezados de agrupación

Como figura 18 muestra, el grupo realmente se utiliza para decorar los datos agrupados, lo que es muy fácil ver qué datos cae en el grupo. Por desgracia, incluso con esta indicación visual de la agrupación, nuestros objetos con formato JSON no realmente la interfaz de usuario que queremos mostrar a nuestros usuarios. Para que funcione de la manera que queremos requiere plantillas.

Plantillas

Una plantilla es una sola raíz de jerarquía de los elementos HTML con "agujeros" opcionales para rellenar datos dinámicos. El atributo de Victoria y enlazarse en la div define los orificios utilizando atributos de enlazar los datos-Victoria. Por ejemplo, nosotros podríamos crear una plantilla para nuestra persona objetos así:

    <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>

Lo que hace este fragmento de HTML una plantilla es el atributo de datos-win-control establecido en el tipo de control de WinJS.Binding.Template. Una vez tengamos nuestra plantilla, necesita hacerlo para rellenar los huecos con los datos:

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

Debido a que la plantilla es sólo otro control (aunque un control que esconde hasta hacerse manualmente), podemos llegar en el div que lo define y tener acceso a su funcionalidad a través de una propiedad conocida llamada winControl. La funcionalidad que queremos acceder a es el método render de la plantilla, que toma un contexto de datos para su uso en el enlace de los atributos de enlazar los datos-ganar y produce un elemento HTML completamente formado para que hagamos lo que queremos con.

Si el control ListView proporciona una plantilla, hará que cada elemento ListView con esa plantilla. De hecho, el control ListView puede tener plantillas para representar los elementos y encabezados de grupo. Para verlo en acción, vamos a actualizar los grupos a objetos, como es más típico:

// 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);

En este código, tenemos dos objetos de grupo, cada uno con una clave y un nombre, y tenemos datos separados y funciones selector de llave que devuelvan al grupo propio o clave del grupo, respectivamente. Con nuestros datos de grupo un poco más real-mundo-como de hecho, se crea una plantilla para el encabezado de grupo, como se muestra en figura 19.

Plantilla de la figura 19 para el encabezado de grupo

    <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>

La plantilla para el encabezado de grupo se crea como una plantilla de elemento. Las plantillas de encabezado y elemento de grupo pasan al control ListView mediante las propiedades groupHeaderTemplate y itemTemplate en el atributo de datos opciones de ganar. Nuestro fancier agrupados datos parece figura 20.

Grouping a Binding List with ListView Headers and Templates
20 Figura una lista de enlace con encabezados de ListView y plantillas de agrupación

OK, tenemos que admitir que no es muy elegante, pero la combinación de grupos y elementos, incluidas las plantillas, muestra el poder de la lista de enlace. De hecho, la lista de enlace es tan útil, es el núcleo del modelo de datos asincrónica expuesto desde el archivo de data.js generado por las plantillas de proyecto de aplicación de Grid y Split, como se muestra en figura 21.

Figura 21 el archivo de Data.js generados por la aplicación de la cuadrícula y el proyecto de aplicación de 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.
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; });
  }
  ...
});
})();

Puedes ver la creación de la lista de enlace vacía, la creación de una versión agrupada de esa lista usando funciones clave y selección de datos sobre los grupos, un pequeño bucle forEach que añade la que función de los elementos a la lista de enlace y por último, un ayudante que hace el filtrado.

¿Dónde estamos?

Comenzamos este artículo excavando en vinculantes, la capacidad de asociar una propiedad de un objeto con un atributo de un elemento HTML. Fuera de la caja, WinJS soporta a inicializadores de enlace unidireccional, único y personalizado, pero el enlace no bidireccional. Enlace es compatible con objetos enlazables individuales así como listas de objetos que implementan la interfaz IListDataSource. El lugar más fácil para obtener una implementación de la interfaz de IListDataSource es mediante el objeto de lista (WinJS.Binding.List) de enlace, que apoya plenamente la ordenación, filtrado y agrupación. También vimos cómo plantillas útiles son cuando lo útil y combinados con el enlace de plantillas y vinculantes son cuando se trata de controles que admiten el enlace de la lista, como el control ListView.

Chris vende es el Vicepresidente de la División de herramientas de desarrollador de Telerik. Es coautor de "Edificio Windows 8 aplicaciones con JavaScript" (Addison-Wesley Professional, 2012), desde que este artículo fue adaptado. Más información sobre ventas y sus diversos proyectos, están disponibles en sellsbrothers.com.

Brandon Satrom es un administrador de programas en la División de la interfaz de usuario de Kendo en Telerik. Es coautor de "Edificio Windows 8 aplicaciones con JavaScript" (Addison-Wesley Professional, 2012), desde que este artículo fue adaptado. Lo puedes seguir en Twitter en twitter.com/BrandonSatrom.

Gracias a los siguientes expertos técnicos por su ayuda en la revisión de este artículo: Chris Anderson, Jonathan Antoine, Michael Weinhardt, Shawn Wildermuth y Josh Williams