Este artigo foi traduzido por máquina.

JavaScript

Ligação de dados em um aplicativo da Windows Store com JavaScript

Chris Sells
Brandon Satrom

Baixar o código de exemplo

Neste artigo, exploraremos a vinculação de dados em um aplicativo de armazenamento Windows construído com JavaScript. Este é um híbrido de outros tipos de aplicativos para Windows 8. É como um aplicativo desktop que é instalado no seu computador, ao contrário de um site da Web. Por outro lado, é como um site em que você pode construir usando HTML5, JavaScript e CSS3. No entanto, em vez de gerar a interface do usuário no lado do servidor, o framework JavaScript para a criação de aplicativos Windows Store e o tempo de execução subjacente do Windows permite a criação de aplicativos com o estado do lado do cliente, armazenamento offline, controles, modelos e ligação — juntamente com uma série de outros serviços.

Ligação de dados é a capacidade de tirar o valor de uma lista de dados, como um conjunto de RSS feeds e usá-lo para preencher um controle, como um ListView. Nós podemos costurar que extraímos usando modelos de dados. Mostraremos como ligação é ainda mais flexível, permitindo a atualização da interface do usuário, como as alterações de dados subjacente, juntamente com a classificação, filtragem e agrupamento.

Quando usamos a vinculação de dados, é muitas vezes no contexto de um controle. Vamos dar uma olhada no ListView e o suporte para vinculação de dados e modelos.

101 De vinculação de dados

O uso de ligação permite que você defina uma associação entre duas propriedades em dois objetos, mais frequentemente, associando a propriedade de um objeto com uma propriedade em um elemento HTML Document Object Model (DOM), como Figura 1 mostra.


Figura 1 ligação entre um atributo em um elemento de destino e uma propriedade de um objeto de origem

O propósito de estabelecer uma ligação é copiar dados entre os dois objetos envolvidos: a fonte de onde vêm os dados e o destino que vai os dados. Você pode pensar que você pode realizar este objetivo usando uma instrução de atribuição simples:

myDestElem.value = mySourceObj.
name;

Fundamentalmente, a atribuição é que ligação faz. No entanto, ligação não é apenas uma descrição de quais dados para cópia e para onde, mas também quando. O "quando" de uma ligação é geralmente um dos seguintes:

  • Ligação unidirecional: Copie os dados ao elemento DOM quando o objeto for alterado. Este é o padrão na biblioteca de JavaScript (WinJS) do Windows.
  • Única ligação: Copie os dados ao elemento DOM quando a ligação é estabelecida pela primeira vez. Isso é o equivalente de atribuição.
  • Ligação bidirecional: Copiar os dados ao elemento DOM quando o objeto muda e copiar os dados para o objeto quando o elemento DOM. Isso não é suportado em WinJS.

Por padrão, WinJS ligação é ligação unidirecional, embora a única ligação é suportada também. Embora WinJS não suporta ligação bidirecional, lá é um lugar agradável para ligar no seu mecanismo de ligação bidirecional favorito, como do jQuery, como você verá.

Objetos de ligação

Para começar, vamos dizer que queremos construir um pequeno navegador para as pessoas em nossas vidas, como mostrado na Figura 2.

Figura 2 ligação de um objeto a um conjunto de elementos HTML

A idéia é que podemos ter um número de pessoas, através de quem podemos navegar, cada um com um nome, idade e uma cor favorita. Como nós usamos os botões anteriores e próximos, podemos navegar para outras pessoas na lista, e se o botão no meio — o relógio — nós comemorar um aniversário aumentando a idade da pessoa atualmente mostrada. A seguir representa o conjunto de pessoas que vai navegar em nossa amostra:

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

A partir de um modelo de projeto aplicativo de navegação Visual Studio 2012 fornece HTML para nós preencher, como mostrado na Figura 3.

Figura 3 o formulário 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>

A parte interessante este HTML é o uso do atributo vitória-vincular dados, que usa o seguinte formato:

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

A sintaxe de ligação de dados-vitória é uma lista delimitada por ponto e vírgula de expressões de ligação. Cada expressão é a combinação de destino propriedade de elemento DOM e uma propriedade do objeto de origem. A sintaxe pontilhada que estamos usando para definir a cor de fundo no estilo para o div cor favorita — isto é, style.backgroundColor—works Propriedades tanto a origem e o destino e treinos em subobjetos, como seria de esperar.

Cada propriedade de destino em uma expressão de vinculação é resolvida contra o elemento HTML que contém o atributo de ligação de dados-vitória. A questão é: O objeto de onde vem contra o que os nomes de propriedade são resolvidos? E a resposta é: o contexto de dados.

Definindo o contexto de dados é parte da operação de vinculação, que estabelece a associação entre o elemento HTML e qualquer objeto é usado como o contexto de dados, como mostrado na Figura 4.

Figura 4 definindo o contexto de dados

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

A função alargamentoTodas no namespace WinJS.Binding é a função que analisa os atributos de vitória de ligar dados de uma determinada hierarquia de elementos HTML, a seção que contém os elementos de entrada e div em nossa amostra. A chamada para alargamentoTodas estabelece as ligações entre os elementos HTML e o contexto de dados, conforme descrito em cada atributo de ligação de dados-vitória. O contexto de dados é o segundo argumento para alargamentoTodas e é usado para resolver os nomes encontrados em cada expressão de vinculação. Os resultados já parecem que estamos, afinal, como mostrado na Figura 2.

Por padrão, se não fizermos nada, já estabelecemos uma conexão de ligação unidirecional entre o objeto de contexto de dados e o elemento DOM. Isso significa que como propriedades a alteração de objeto de origem de dados, esperamos que a saída para mudar também, como mostrado na Figura 5.

Figura 5 como propriedades sobre a mudança de fonte de dados, assim que faz a saída

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

Nossa implementação do manipulador click do botão de aniversário procura o elemento atual e altera uma propriedade, especificamente a idade. No entanto, não estamos completamente onde precisamos ser para obter a interface do usuário para atualizar automaticamente.

O problema é que um objeto JavaScript padrão não suporta qualquer protocolo de notificação para informar as partes interessadas — como uma ligação — que seus dados foi alterado. Para adicionar a notificação protocolo é uma questão de chamar o método do namespace WinJS.Binding, como mostrado no Figura 6.

Figura 6 Adicionar o protocolo de notificação

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

O método de "como" envolve cada objeto, fornecendo o protocolo de notificação de vinculação para que cada alteração de propriedade notifica quaisquer ouvintes de ligação (como nossos HTML elementos vinculados). Com este código no lugar, alterando a idade de uma pessoa é refletida na interface do usuário, como Figura 7 mostra.


Figura 7, alterando os dados subjacentes automaticamente atualiza os elementos HTML acoplado

Nós já binding objeto um única pessoa para o conjunto de elementos HTML para exibição, mas você pode processar as expressões de ligação de dados em atributos de vitória-ligar dados com um tipo diferente de contexto de dados, como mostrado na Figura 8.

Figura 8 as expressões de ligação de dados de processamento

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

Aqui é onde podemos fazer uma mudança entre passar em um único pedaço de dados de "modelo" do nossa aplicação (isto é, o conjunto de dados que não tem nada a ver com a exibição de si) para agrupar os dados que é apropriados para nossa "visão" de que o modelo (no caso, a pessoa atual para ver). Chamamos essa variável "modelo de visualização" após uma técnica famosa e útil para a implementação de interfaces de usuário chamados Model-View-ViewModel (MVVM). Uma vez que nós construímos o nosso modelo de vista como um objeto de ligação, como as propriedades subjacentes alterar (a pessoa, no nosso caso) a visualização é atualizada. Podemos então vincular nossa visão para o modelo de exibição assim que em nosso próximo e voltar botão manipuladores — como podemos mudar o que a pessoa que nós gostaríamos de ver — a vista é notificada. Para este trabalho, vamos precisar atualizar o HTML para usar o modelo de exibição em vez da pessoa diretamente, como mostrado no Figura 9.

Figura 9 atualização do HTML para usar o modelo de exibição

 

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

A Figura 10 mostra o resultado.


Figura 10 você pode reassociar objetos diferentes para o mesmo conjunto de elementos HTML

Além de binding objetos para elementos, ligação também permite que você escute simplesmente para um valor de mudar. Por exemplo, agora como podemos alterar o índice para o valor atual quando o usuário clica nos botões anteriores ou seguinte, temos de lembrar-se de escrever o código para alterar campo de pessoa do modelo de exibição para corresponder. No entanto, você pode usar vinculação própria para ajudar aqui, como mostrado na Figura 11.

Figura 11 expressões de vinculação de reprocessamento

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

Em vez de uma simples variável para armazenar o índice para a pessoa atualmente mostrada, acrescentamos o índice à pessoa atualmente vista ao nosso modelo de vista ligáveis. Todos os objetos ligáveis têm um método de ligação, que permite ouvir as alterações às propriedades do objeto (a propriedade atual neste exemplo). Quando o usuário clica nos botões anteriores ou seguinte, nós simplesmente alterar o índice da pessoa atual a ser mostrado e deixar o processo manipulador de vincular os atributos de ligação de dados-vitória para o HTML que mostra a pessoa atual.

Se você quiser parar de ouvir para vincular eventos, você pode chamar o método unbind.

Agora, como dissemos, tudo o que você viu trabalha contra o padrão: ligação unidirecional. No entanto, se você gostaria de definir outros tipos de ligação ou participar no processo de vinculação propriamente dito, você pode fazer isso com um inicializador de ligação.

Inicializadores

Um inicializador é o terceiro parâmetro opcional para uma expressão de vinculação que especifica uma função para chamar quando a ligação é estabelecida:

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

Você fornecer um inicializador como parte de uma expressão de vinculação, se você quiser participar ou até mesmo substituir o comportamento de vinculação existente — por exemplo, para executar uma conversão de dados ou até mesmo ligar ligação bidirecional de jQuery. Um inicializador de vinculação é uma função que assume para a ligação de uma forma padrão e tem a seguinte assinatura:

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

Os detalhes da implementação de um inicializador personalizado estão além do escopo deste artigo, mas WinJS tem vários inicializadores built-in que você pode aproveitar. Por exemplo, se você gostaria de fazer uma vez em vez de ligação unidirecional, você pode usar a função única do namespace WinJS.Binding:

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

Na outra extremidade do espectro, ao realizar a ligação unidirecional, é frequentemente útil realizar a conversão de dados (também conhecida como transformação de dados). Por exemplo, imagine que queríamos explicitar as idades das pessoas em nossa vida:

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

A função de conversor no namespace WinJS.Binding fornece a parte mais difícil da implementação do inicializador; tudo que você tem que fazer é fornecer uma função para executar a conversão real e ele será chamado como as alterações de valor da fonte. Usá-lo no HTML olha como você esperaria:

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

Você pode ver os resultados em Figura12.


Figura 12, traduzindo uma idade numérica de palavras através da conversão de dados

A vinculação de valores um em um momento é útil, mas ainda mais útil — especialmente para os apps da loja do Windows — é obrigatório coleções de valores de uma vez. Para isso, temos a lista de ligação.

Uma lista de ligação

Imagine um exemplo simples de usar um ListView com uma coleção de valores:

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

Aqui estamos criando um ListView controle declarativamente em HTML que está vinculado à propriedade dataSource de um objeto global itens. Nosso JavaScript, é fácil criar e preencher o objeto de itens como uma lista de ligação:

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

Neste código criamos uma lista de ligação (uma instância do tipo lista do namespace WinJS.Binding) e temos um loop sobre uma matriz de valores, usando cada um para criar um tempo limite, que é uma promessa que será acionado em algum momento no futuro, de acordo com o argumento que você passar (milissegundos). Quando cada timeout for concluído, vamos ver o ListView receber um valor adicional, como Figura 13 mostra.


Figura 13 o ListView atualização como lista de ligação subjacente atualiza

O HTML não fornece uma ID para o ListView, nem faz o JavaScript interagir com o ListView de qualquer maneira. Em vez disso, o HTML e o JavaScript tanto encontro nos itens de lista de ligação. É a lista de vinculação que implementa a coleção binding API (chamado IListDataSource). Em vez de fazer você programa contra IListDataSource diretamente — não é particularmente favorável ao programador — a lista de ligação expõe sua implementação de IListDataSource através da propriedade dataSource.

Para fornecer uma API que é tão familiar quanto possível para os programadores de JavaScript, a lista de ligação implementa uma API semelhante e semântica similar como a matriz interna suporta — por exemplo, empurrar, pop, cortar, juntar e assim por diante. Como uma comparação, aqui está como funciona o built-in array de JavaScript:

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

A lista de vinculação comporta da mesma forma, exceto que em vez de usar um indexador — ou seja, colchetes — expõe itens 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";

Classificação e filtragem

Além da API familiar, a lista de ligação foi construída com app Store Windows construção necessidades em mente. Você já viu como o dataSource propriedade permite que você ligue para o ListView controle. Além disso, você pode estar interessado em classificar e filtrar os dados. Por exemplo, na aqui nossa lista de pessoas novamente, desta vez embrulhada em uma lista de ligação:

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 classificar uma lista de ligação, chamando o método createSorted, passando em uma função de classificação, ou filtrá-lo chamando o método createFiltered, passando em uma função de filtragem. O resultado de chamar um destes métodos de criar é uma visão sobre os dados que se parece e age como uma outra instância da lista de ligação, e nós pode vinculá-lo a um ListView, como Figura 14 mostra.


Figura 14, uma lista de ligação de filtragem

Em vez de fornecer uma cópia dos dados subjacentes, o createSorted e createFiltered métodos retornam uma exibição ao vivo sobre os dados existentes. Isso significa que quaisquer alterações aos dados subjacentes são refletidas nas vistas e serão mostradas em quaisquer controles acoplados. Por exemplo, nós poderia adicionar um menor à lista subjacente:

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

Mesmo que nós estamos mudando os dados subjacentes, o modo de exibição classificado será atualizado e o ListView será notificado da mudança, como Figura 15 mostra.


Figura 15 classificar uma lista de ligação

Também, porque a visão de criar métodos olha e sente como uma lista de ligação, mais você pode classificar ou filtrar a exibição de uma forma empilhada:

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

Os resultados de ligação para a exibição filtrada e classificada resultante devem ser uma surpresa (ver Figura 16).


Figura 16 classificar e filtrar uma lista de ligação

Tenha cuidado ao empilhamento que fazê-lo na ordem correta. No caso de filtragem, se você classificar ou agrupar primeiro e, em seguida, filtrar, você está fazendo mais trabalho do que você precisa. Além disso, cada camada view é sobrecarga, assim que você vai querer certificar-se que você empilha-los apenas tão profundamente quanto necessário.

Agrupamento

Além de classificação e filtragem de ligação de dados de lista, você pode agrupá-lo também por alguns critérios de dados. Por exemplo, adultos e menores funcionaria bem para nossos dados de exemplo:

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

O valor de retorno da função de agrupamento é um valor de seqüência de caracteres que identifica o grupo — no nosso caso, a seqüência de caracteres "menor" ou a seqüência de caracteres "adulto". Ligação para a exibição dos dados agrupada mostra os dados organizados pelo grupo — isto é, de todos os itens de cada grupo antes de passar para o próximo grupo, como Figura 17 mostra.


Figura 17 agrupar uma lista de ligação

Este exemplo mostra apenas dois grupos, mas você pode ter qualquer número de grupos. Além disso, como createSorted e createFiltered, o método createGrouped retorna uma exibição sobre dados ao vivo, para que as alterações nos dados subjacentes serão refletidas em vincular destinos.

No entanto, enquanto é evidente para nós, os desenvolvedores, que nós está classificando os grupos — primeiro os adultos e, em seguida, os menores — não é claro para os usuários do nosso programa, porque não há nenhum indicador visual de agrupamento. Para pedir o ListView para fornecer um indicador visual de agrupamento, o ListView permite que você especifique dois conjuntos de dados: a lista de itens agrupados e os próprios grupos. Configurando o ListView com ambos os conjuntos de dados se parece com isso:

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

Depois que criamos a exibição agrupada da lista de ligação, a propriedade de grupos expõe uma lista desses grupos para que o ListView pode usá-los. No entanto, antes de nós pode fazer o trabalho, também precisamos ir para trás ao nosso uso da função 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, quando foram de agrupamento, nós apenas necessário fornecer uma função que poderia fazer o agrupamento com base em algum identificador único grupo. No entanto, se queremos realmente mostrar os grupos para o usuário, precisamos de outro método que pode extrair os próprios grupos (se você quiser escolher a ordem dos grupos, você poderia fornecer um terceiro método para o método createGroup que faz a classificação). Em ambos os casos, estamos fornecendo uma seqüência de caracteres para representar o grupo, bem como para criar a lista de grupos, que funciona muito bem, como você pode ver no Figura 18.


Figura 18 agrupar uma lista de ligação com cabeçalhos de ListView

Como Figura 18 mostra, o grupo é realmente usado para decorar os dados agrupados, tornando muito fácil para ver quais dados cai em que grupo. Infelizmente, mesmo com esta indicação visual de agrupamento, nossos objetos JSON formatado não realmente a interface do usuário, queremos mostrar aos nossos usuários. Para este trabalho da forma que queremos requer modelos.

Modelos

Um modelo é uma hierarquia de raiz única de elementos HTML com o opcionais "buracos" para preencher dados dinâmicos. O atributo de dados-vitória-bind no div define os furos usando atributos de dados-vitória-bind. Por exemplo, poderíamos criar um modelo para nossa pessoa objetos da seguinte forma:

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

O que torna este pedaço de um modelo HTML é o atributo de dados-win-controle definido para o tipo de controle de WinJS.Binding.Template. Uma vez que temos o nosso modelo, você precisa torná-lo para preencher os buracos com dados:

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

Porque o modelo é apenas um outro controle (apesar de um controle que esconde-se até processado manualmente), podemos chegar para o div que o define e obter acesso a sua funcionalidade através de uma propriedade bem conhecida chamado winControl. A funcionalidade que deseja acessar é o método de renderização do modelo, que leva a um contexto de dados para uso em ligação os atributos de ligação de dados-vitória e produz um elemento HTML totalmente formado para que possamos fazer o que queremos com.

Se você fornecer o ListView um modelo, ele processará cada item no ListView com esse modelo. Na verdade, o ListView pode ter modelos para o processamento de itens e cabeçalhos de grupo. Para ver isso em ação, vamos primeiro atualizar os grupos de objetos, como é mais 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);

Nesse código, temos dois objetos de grupo, cada um com uma chave e um nome, e nós temos dados separados e funções do seletor de chave que retornam o grupo propriamente dito ou chave do grupo, respectivamente. Com nossos dados de grupo feitos um pouco mais real-mundo-like, é criado um modelo para o cabeçalho de grupo, como mostrado na Figura 19.

Figura 19 modelo para o cabeçalho 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>

O modelo para o cabeçalho de grupo é criado como um modelo de item. Os modelos de item e o cabeçalho de grupo são passados para o controle ListView via o groupHeaderTemplate e itemTemplate Propriedades no atributo opções de vitória de dados. Nossos sofisticados agrupado dados parece Figura 20.


20 Figura uma lista de ligação com cabeçalhos de ListView e os modelos de agrupamento

OK, vamos admitir que não é muito extravagante, mas a combinação de grupos e itens, incluindo os modelos, mostra o poder da lista de ligação. Na verdade, a lista de ligação é tão útil, é o núcleo do modelo de dados assíncrono exposto do data.js arquivo gerado pelo aplicativo grade e aplicação de Split modelos de projeto, como mostrado na Figura 21.

Figura 21 o arquivo Data.js gerado pelo aplicativo de grade e projeto de aplicativo 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; });
  }
  ...
});
})();

Você pode ver a criação da lista vazia de vinculação, a criação de uma versão agrupada dessa lista usando funções chave e seleção de dados sobre os grupos, um pouco forEach loop que adiciona que os itens para a lista de ligação e, finalmente, um auxiliar função que faz a filtragem.

Onde estamos?

Começamos este artigo escavar em ligação, a capacidade de associar uma propriedade em um objeto com um atributo em um elemento HTML. Fora da caixa, WinJS suporta inicializadores de ligação unidirecional, única e personalizada, mas a ligação não bidirecional. Vinculação é suportada em objetos ligáveis único, bem como listas de objetos que implementam a interface IListDataSource. O lugar mais fácil para obter uma implementação da interface IListDataSource é através do objeto de lista (WinJS.Binding.List) de vinculação, que apoia plenamente a classificação, filtragem e agrupamento. Vimos também como modelos úteis são quando combinado com ligação e útil como modelos e vinculação são quando se trata de controles que suportam a ligação da lista, como o ListView.

Chris vende é o vice presidente da divisão de ferramentas do desenvolvedor Telerik. Ele é co-autor de "Building Windows 8 Apps com JavaScript" (Addison-Wesley Professional, 2012), de que este artigo foi adaptado. Mais informações sobre a vende e seus vários projetos, estão disponíveis em sellsbrothers.

Brandon Satrom é gerente de programa de divisão de interface do usuário do Kendo Telerik. Ele é co-autor de "Building Windows 8 Apps com JavaScript" (Addison-Wesley Professional, 2012), de que este artigo foi adaptado. Você pode segui-lo no Twitter em twitter.com/BrandonSatrom.

Agradecemos aos seguintes especialistas técnicos pela revisão deste artigo: Chris Anderson, Antoine de Jonathan, Michael Weinhardt, Shawn Wildermuth e Josh Williams