Como personalizar dados do modelo do Visual Studio (XAML)

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente]

Nos modelos Hub/Pivot, Hub, Pivot, Grade e Dividido, o código que obtém os dados necessários aos aplicativos estão no arquivo data.js. Esse arquivo representa uma fonte de dados de exemplo do aplicativo. O arquivo data.js inclui dados estáticos que, em geral, precisam ser substituídos por dados dinâmicos. Por exemplo, se o aplicativo fizer uma única solicitação de xhr para obter dados RSS ou JSON, talvez você queira incluir esse código no data.js. A inclusão do código permite que você use com facilidade seus próprios dados, sem modificar o modelo de dados presente nos modelos.

Dica  Os modelos Hub/Pivot, Hub e Pivot também recuperam dados estáticos de arquivos .resjson que aceitam globalização. Para saber mais, veja Exemplo de vinculação de dados para a interface do usuário no modelo Hub/Pivot, Hub e Pivot.

 

É necessário prestar atenção a alguns fatores ao adicionar os seus próprios dados a um aplicativo:

  • Grupos e itens estão vinculados intrinsecamente. O aplicativo espera que os dados estejam organizados em grupos. Você pode desvincular os dois na sua própria implementação, mas precisa mudar o código para que a implementação funcione. Este tópico mostra como os grupos são usados no modelo de dados do modelo.
  • Ao implementar dados personalizados para um aplicativo em data.js, verifique se os nomes de propriedades inerentes aos dados personalizados foram mapeados para os nomes de propriedades usados pelo modelo. É possível mudar os nomes usados pelo modelo, mas isso exige mais revisão do código. Este tópico mostra alguns exemplos de como fazer isso.

Itens e grupos

Dados de modelo são armazenados em uma WinJS.Binding.List. Este código mostra a declaração de uma lista no arquivo data.js.

var list = new WinJS.Binding.List();

Uma matriz de dados de itens (neste exemplo, sampleItems) é transferida para WinJS.Binding.List pela função push, conforme mostrado aqui:

generateSampleData.forEach(function (item) {
    list.push(item);
});

A WinJS.Binding.List inclui uma lógica interna para lidar com o agrupamento de dados. A matriz sampleItems inclui uma propriedade group que identifica o grupo ao qual o contém o item pertence (nos dados de exemplo, os grupos são especificados na matriz sampleGroups). Esta é a matriz de dados de itens na função generateSampleData:

function generateSampleData() {
    // . . .
    var sampleGroups = [
        { key: "group1", title: "Group Title: 1", // . . .
        // . . .
    ];

    var sampleItems = [
        { group: sampleGroups[0], title: "Item Title: 1", // . . .
        // . . .
    ];

    return sampleItems;
}

Na hora de modificar o aplicativo para incluir dados personalizados, é interessante seguir o mesmo padrão para agrupar os seus dados. No caso de conjuntos de dados menores, nós recomendamos o uso de WinJS.Binding.List para ListView. Se não agrupar os itens, você ainda poderá usar uma WinJS.Binding.List, mas precisará modificar o código do modelo sempre que esse modelo solicitar dados baseados em grupo.

Dica  WinJS.Binding.List é uma fonte de dados síncrona que usa uma matriz JavaScript. No caso de conjuntos de dados muito grandes, com milhares de itens, talvez seja necessário usar uma fonte de dados assíncrona. Para saber mais, veja Usando ListView.

 

A função createGrouped de WinJS.Binding.List especifica como agrupar os itens usando uma chave de grupo e um valor de grupo de itens. Essa função é chamada em data.js. key e group são nomes de propriedades especificados nas matrizes de dados de amostra.

var groupedItems = list.createGrouped(
    function groupKeySelector(item) { return item.group.key; },
    function groupDataSelector(item) { return item.group; }
);

Quando o aplicativo de modelo precisa de uma lista de itens, ele chama getItemsFromGroup, que retorna uma WinJS.Binding.List contendo apenas os itens pertencentes ao grupo especificado.

function getItemsFromGroup(group) {
    return list.createFiltered(function (item) {
        return item.group.key === group.key;
    });
}

Dica  Funções como getItemsFromGroup, que chamam createFiltered, criam uma nova projeção do WinJS.Binding.List, e pode ser necessário descartar o objeto retornado se você navegar para fora de uma página. Para descartar o objeto, chame o método WinJS.Binding.List.dispose.

 

A função define da Biblioteca do Windows para JavaScript expõe os dados a serem usados no aplicativo especificando um namespace nomeado Data, acompanhado de um conjunto de funções públicas de membro.

WinJS.Namespace.define("Data", {
    items: groupedItems,
    groups: groupedItems.groups,
    getItemReference: getItemReference,
    getItemsFromGroup: getItemsFromGroup,
    resolveGroupReference: resolveGroupReference,
    resolveItemReference: resolveItemReference
});

Se você quiser definir uma fonte de dados diferente para cada página em seu aplicativo, ou um modelo de dados diferente, você precisará substituir todas as chamadas para esses membros no código JavaScript.

Vinculando dados de itens e grupo à interface do usuário

O código a seguir mostra um exemplo de marcação para o controle ListView. A fonte de dados para o ListView é especificada na propriedade itemDataSource, mostrada aqui. Este exemplo é de split.html no modelo Dividido.


<div class="itemlist win-selectionstylefilled" aria-label="List of this group's items" data-win-control="WinJS.UI.ListView" data-win-options="{
    layout: {type: WinJS.UI.ListLayout},
    currentItem: {type: WinJS.UI.ObjectType.item, index: 0, hasFocus: true},
    selectionMode: 'single',
    swipeBehavior: 'none',
    tapBehavior: 'toggleSelect',
    itemDataSource: select('.pagecontrol').winControl.itemDataSource,
    itemTemplate: select('.itemtemplate'),
    onselectionchanged: select('.pagecontrol').winControl.selectionChanged
    }">
</div>

No código anterior, uma propriedade itemDataSource associada à página é atribuída à propriedade itemDataSource do controle ListView.

Nos modelos, os dados costumam ser vinculados à interface do usuário na função init ou na função ready, que é definida no arquivo .js associado a cada página HTML. O código a seguir está contido na função init para split.html. Nesse código, o aplicativo obtém uma referência de grupo e então chama getItemsFromGroup, cuja implementação se dá no data.js. Conforme mencionado anteriormente, getItemsFromGroup retorna uma WinJS.Binding.List contendo apenas os itens do grupo especificado.

this._group = Data.resolveGroupReference(options.groupKey);
this._items = Data.getItemsFromGroup(this._group);

Em seguida, associamos a lista retornada de getItemsFromGroup à propriedade itemDataSource da página, que associa os dados a ListView, e também especificamos o manipulador para seleção de itens (_selectionChanged).


this.itemDataSource = this._items.dataSource;
this.selectionChanged = ui.eventHandler(this._selectionChanged.bind(this));

Para exibir cada item no ListView, o aplicativo associa um modelo ao ListView, conforme aqui ilustrado. Esse código aparece na marcação do controle ListView e usa a propriedade itemTemplate para especificar um elemento DIV com um nome de classe de itemtemplate.

itemTemplate: select('.itemtemplate')

Modelos do WinJS, que se baseiam em WinJS.Binding.Template, são usados para formatar e exibir várias instâncias de dados. O modelo de dados de uso mais comum em modelos de Grade e Dividido é o modelo de item usado para exibir itens em um ListView. Como ocorre com cada um dos objetos de modelo WinJS, é possível declará-lo adicionando um atributo data-win-control e definindo esse atributo como WinJS.Binding.Template. Este é o código HTML para itemtemplate em split.html:

<div class="itemtemplate" data-win-control="WinJS.Binding.Template">
    <div class="item">
        <img class="item-image" src="#" data-win-bind="src: backgroundImage; alt: title" />
        <div class="item-info">
            <h3 class="item-title win-type-ellipsis" 
                data-win-bind="textContent: title"></h3>
            <h6 class="item-subtitle win-type-ellipsis"
                data-win-bind="textContent: author"></h6>
        </div>
    </div>
</div>

itemtemplate é usado para itens ListView arbitrários. Os itens do ListView podem ser grupos ou itens de dados individuais, dependendo do contexto. Em items.html, por exemplo, os itens do ListView são grupos.

Importante  Os modelos criados com WinJS.Binding.Template não se relacionam ao projeto do Visual Studio, nem a modelos de item, como Grade e Dividido.

 

Os modelos de projeto esperam que determinadas propriedades estejam presentes nos dados, e essas propriedades são explicitamente nomeadas no HTML. No código HTML anterior para itemtemplate, você pode encontrar propriedades como title e subtitle. Se os dados de aplicativo personalizados não usarem esses nomes de propriedades, você precisará executar um dos procedimentos a seguir:

  • Mapear seus dados para os nomes dessas propriedades (geralmente em data.js) ou
  • Corrija todas as referências de código HTML e .js estabelecidas para essas propriedades no código do modelo, de modo que correspondam aos nomes das propriedades usadas nos seus dados. As propriedades usadas nos modelos incluem:
    • title, subtitle, description e backgroundImage (propriedades de grupo e item)
    • group e content (propriedades de item)
    • key (propriedade de grupo)

Seguindo o mesmo padrão do modelo WinJS, o modelo Aplicativo de Grade também usa um headerTemplate em algumas de suas páginas HTML.

Exemplo de vinculação de dados para a interface do usuário no modelos Hub/Pivot, Hub e Pivot

No Visual Studio, os modelos de projeto Hub/Pivot, Hub e Pivot demonstram como implementar duas fontes de dados diferentes:

  • Dados estáticos globalizados armazenados em arquivos de recursos .resjson. Esses dados são usados nos controles (PivotItem ou HubSection) em algumas das seções de aplicativo.
  • Dados de exemplo em data.js, que representam o modelo de dados. Esse arquivo é o mesmo nos modelos Grade e Dividido. Esses dados de exemplo são usados no controle ListView em uma das seções de aplicativo.

As funções declarativas em HTML são inicialmente usadas para obter dados de exemplo, e o modelo de dados é síncrono por padrão. Personalizar os modelos para usar dados dinâmicos em todas as seções requer algumas alterações no hub.html, no hub.js e em outros arquivos. Os seguintes aplicativos de exemplo mostram como personalizar os modelos Hub/Pivot e Hub para suporte de dados assíncronos:

Como os dados globalizados no arquivo .resjson são substituídos facilmente, os aplicativos de exemplo deixam esse arquivo de recurso sem modificação. Nos aplicativos de exemplo, os dados para os elementos <img> e o controle ListView presentes nas seções Hub/Pivot são recuperados de forma assíncrona.

Para saber mais sobre como fornecer dados globalizados em arquivos .resjson, veja Guia de início rápido: traduzindo recursos da interface do usuário.

Para dar suporte à vinculação de dados assíncronos ao controle ListView de Hub/Pivot, primeiro substitua as variáveis globais em hub.js que chamam o modelo de dados:

var section3Group = Data.resolveGroupReference("group4");
var section3Items = Data.getItemsFromGroup(section3Group);

por estas declarações de variável:


var section3Group = "group2";
var section3Items;

Também tem que modificar a implementação das funções declarativas em hub.js. Na implementação do modelo padrão, essas funções dependem dos dados que já estão disponíveis (por exemplo, a chamada de section3Items.dataSource). Substitua este código:

section3DataSource: section3Items.dataSource,

section3HeaderNavigate: util.markSupportedForProcessing(function (args) {
    nav.navigate("/pages/section/section.html", { title: args.detail.section.header, 
        groupKey: section3Group.key });
}),

section3ItemNavigate: util.markSupportedForProcessing(function (args) {
    var item = Data.getItemReference(section3Items.getAt(args.detail.itemIndex));
    nav.navigate("/pages/item/item.html", { item: item });
}),

por:


section3DataSource: null,

section3HeaderNavigate: util.markSupportedForProcessing(function (args) {
    nav.navigate("/pages/section/section.html", { title: args.detail.section.header,
        groupKey: section3Group });
}),

section3ItemNavigate: util.markSupportedForProcessing(function (args) {
    var itemSet = section3Items;
    var itemObj = itemSet.getAt(args.detail.itemIndex);
    var item = [itemObj.group.key, itemObj.title, itemObj.backgroundImage];

    nav.navigate("/pages/item/item.html", { item: item });
}),

Esse código define a função section3DataSource como nula, para evitar tentar vincular os dados antes que eles estejam prontos. Vamos definir a fonte de dados mais adiante, em uma função de vinculação de dados (_bindData ou bindListView, dependendo do aplicativo de exemplo).

A função de vinculação de dados é chamada assim que os dados ficam disponíveis. Para possibilitar isso, adicionamos um ouvinte para o evento dataReady do modelo de dados, definido no aplicativo de exemplo em data.js.


this._observer = Data.getObservable();
this._observer.addEventListener('dataReady', this.onDataCompleted.bind(this));

O aplicativo chama a função de vinculação de dados do manipulador de eventos onDataCompleted (não mostrado). O código da função _bindData do exemplo de modelo Hub é mostrado aqui. Nesse código, definimos a propriedade itemDataSource de ListView.


_bindData: function (context, grp1Items, grp2Items) {

    var self = context;

    // . . .

    self._items = grp2Items;
    section3Items = self._items;
    self._section3lv.itemDataSource = self._items.dataSource;

    // . . .   

},

Se o botão Voltar for usado para navegar para a página, a função de vinculação de dados será chamada diretamente da função de inicialização de página, porque não é necessário aguardar novos dados.

Dica  No código do modelo de Hub, para consultar o DOM para o elemento ListView (armazenado em _section3lv), o aplicativo chama uma função _hubReady do manipulador de eventos loadingstatechanged do controle do Hub. Esse evento é ativado apenas quando a página de hub termina de ser carregada. O uso desse manipulador de eventos permite consultar o DOM para obter o elemento DIV aninhado associado ao ListView.

 

Para obter o código completo para fazer os dados assíncronos funcionarem nos modelos Hub/Pivot e Hub, veja Leitor da Web JSON que utiliza o modelo Hub/Pivot e Leitor da Web JSON que utiliza o modelo Hub. Além das personalizações aqui descritas, fizemos as seguintes alterações no aplicativo de exemplo:

  • Incluímos código no modelo de dados (data.js) para recuperar dados usando uma solicitação de xhr e para analisar os dados JSON (do Flickr).
  • Incluímos código no modelo de dados para manipular várias solicitações de dados e para ativar o evento dataReady quando os dados são retornados.
  • Incluímos uma caixa de entrada na interface do usuário para solicitar novos dados.
  • Incluímos uma barra de progresso para mostrar o status da solicitação de dados.
  • Fizemos adições no estilo CSS para a caixa de entrada e a barra de progresso.
  • Funções incluídas para inicializar a página depois que o controle de Hub for totalmente carregado (como _hubReady ou _hubReadyPhone).
  • Modificamos os elementos de Hub/Pivot ou Hub <img> para dar suporte a eventos de clique (os arquivos modificados são específicos para o modelo).
  • Modificamos os arquivos para vincular dados assíncronos aos elementos de Hub/Pivot ou Hub <img> (os arquivos modificados são específicos para o modelo).
  • Modificamos o hub.js para dar suporte à navegação para imagens dos elementos de Hub/Pivot ou Hub <img> (os arquivos modificados são específicos para o modelo).
  • Modificamos item.html e item.js para dar suporte à exibição de imagens únicas.

Exemplo de associação de dados à interface do usuário (Grade e Dividido)

Esta seção mostra como implementar a sua própria fonte de dados em modelos de projeto Grade e Dividido. O código de exemplo, aqui, usa uma solicitação xhr para gerar dados RSS.

Importante  Para implementar dados assíncronos no modelo de Hub, veja o tópico sobre como associar dados à interface do usuário no modelo de Hub.

 

Atualizando data.js

  1. Crie um novo projeto no Visual Studio. Use o modelo de projeto Aplicativo Dividido ou Aplicativo de Grade.

  2. Em data.js, adicione as seguintes variáveis próximas ao início do arquivo, após a declaração use strict:

    var lightGray = "data:image/png;base64,
        iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
    var mediumGray = "data:image/png;base64,
        iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";
    
  3. No data.js, remova a função generateSampleData que contém estas matrizes: sampleGroups e sampleItems.

    Vamos substituir esses dados por dados RSS. Não usaremos a maioria das variáveis de espaço reservado, como groupDescription, mas reutilizaremos as imagens de espaço reservado, lightGray e mediumGray, para que o novo código funcione.

  4. No mesmo local em que você removeu generateSampleData, adicione o seguinte código ao data.js:

    
    function getFeeds() {
        // Create an object for each feed.
        blogs = [
            {
                key: "blog1", url: 
           'https://windowsteamblog.com/windows/b/developers/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "blog2", url: 
           'https://windowsteamblog.com/windows/b/windowsexperience/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            }]
        // Get the content for each feed in the blog's array.
        blogs.forEach(function (feed) {
            feed.dataPromise = feed.acquireSyndication(feed.url);
            dataPromises.push(feed.dataPromise);
        });
    
        // Return when all asynchronous operations are complete
        return WinJS.Promise.join(dataPromises).then(function () {
            return blogs;
        });
    
    };
    
    function acquireSyndication(url) {
        return WinJS.xhr(
        {
            url: url,
            headers: { "If-Modified-Since": "Mon, 27 Mar 1972 00:00:00 GMT" }               
        });
    }
    
    function getBlogPosts() {
        getFeeds().then(function () {
            // Process each blog.
            blogs.forEach(function (feed) {
                feed.dataPromise.then(function (articlesResponse) {
                    var articleSyndication = articlesResponse.responseXML;
    
                    // Get the blog title and last updated date.
                    if (articleSyndication) {
                        // Get the blog title and last updated date.
                        feed.title = articleSyndication.querySelector(
                            "feed > title").textContent;
                        var ds = articleSyndication.querySelector(
                            "feed > updated").textContent;
                        var date = ds.substring(5, 7) + "-" +
                            ds.substring(8, 10) + "-" + ds.substring(0, 4);
                        feed.updated = "Last updated " + date;
                        // Process the blog posts.
                        getItemsFromXml(articleSyndication, blogPosts, feed);
                    }
                    else {
                        // There was an error loading the blog. 
                        feed.title = "Error loading blog";
                        feed.updated = "Error";
                        blogPosts.push({
                            group: feed,
                            key: "Error loading blog",
                            title: feed.url,
                            author: "Unknown",
                            month: "?",
                            day: "?",
                            year: "?",
                            content: "Unable to load the blog at " + feed.url
                        });
                    }
                });
            });
        });
    
        return blogPosts;
    }
    
    function getItemsFromXml(articleSyndication, blogPosts, feed) {
        var posts = articleSyndication.querySelectorAll("entry");
        // Process each blog post.
        for (var postIndex = 0; postIndex < posts.length; postIndex++) {
            var post = posts[postIndex];
            // Get the title, author, and date published.
            var postTitle = post.querySelector("title").textContent;
            var postAuthor = post.querySelector("author > name").textContent;
            var pds = post.querySelector("published").textContent;
            var postDate = pds.substring(5, 7) + "-" + pds.substring(8, 10)
                + "-" + pds.substring(0, 4);
            // Process the content so that it displays nicely.
            var staticContent = toStaticHTML(post.querySelector(
                "content").textContent);
            // Store the post info we care about in the array.
            blogPosts.push({
                group: feed, key: feed.title, title: postTitle, 
                author: postAuthor, pubDate: postDate, 
                backgroundImage: mediumGray, content: staticContent
            });
        }
    }
    
  5. Em data.js, substitua este código:

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

    por:

    var dataPromises = [];
    var blogs;
    
    var blogPosts = new WinJS.Binding.List();
    
    var list = getBlogPosts();
    var groupedItems = list.createGrouped(
        function groupKeySelector(item) { return item.group.key; },
        function groupDataSelector(item) { return item.group; }
    );
    

    Vamos reutilizar o código de createGrouped que especifica o agrupamento — as funções groupKeySelector e groupDataSelector.

    Como alteramos alguns dos nomes de propriedades usados nos modelos, será preciso fazer algumas atualizações nas páginas HTML. Especificamente, para qualquer propriedade subtitle que faça referência a um item (e não a um grupo), é preciso mudar o subtitle pelo author. Para qualquer propriedade description que faça referência a um item, é necessário trocar description por pubDate.

    Para implementar essas mudanças na interface do usuário, veja algumas das seções a seguir:

    • Vinculando dados de exemplo à Interface do Usuário no modelo Dividido
    • Vinculando dados de exemplo à Interface do Usuário no modelo de Grade

Vinculando dados de exemplo à Interface do Usuário no modelo Dividido

  1. Para usar o código de exemplo no modelo Dividido, abra split.html.

  2. Em split.html, precisamos alterar algumas linhas no elemento DIV que tem um nome de classe itemtemplate. Altere esta linha:

    
    <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: subtitle"></h6>
    

    para isto:

    <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: author"></h6>
    
  3. Também no split.html, a seção de artigo (articlesection) contém informações de cabeçalho que precisamos atualizar. Altere esta linha:

    <h4 class="article-subtitle" data-win-bind="textContent: subtitle"></h4>
    

    para isto:

    <h4 class="article-subtitle" data-win-bind="textContent: author"></h4>
    
  4. Abra items.html.

    O modelo de item WinJS definido no código HTML contém itens arbitrários do ListView. Em items.html, o modelo é usado para mostrar grupos (blogs). A única propriedade de grupo que precisamos mudar aqui é subtitle.

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: subtitle"></h6>
    
  5. Altere a propriedade subtitle para updated, como ilustrado aqui:

    <h6 class="item-subtitle win-type-ellipsis"
        data-win-bind="textContent: updated"></h6>
    
  6. Salve o projeto e pressione F5 para depurar o aplicativo.

    Você vê o título da página imediatamente, mas há um pequeno atraso enquanto os dados do feed são recuperados. Quando todas as promessas estiverem cumpridas, você verá cada blog na home page. clique em um dos blogs para ver as postagens no modo de exibição mestre/detalhado.

Vinculando dados de exemplo à Interface do Usuário no modelo de Grade

Antes de seguir estas etapas, atualize o arquivo data.js conforme descrito em Exemplo de associação de dados à interface do usuário.

  1. Para usar o código de exemplo RSS no modelo Grade, abra groupDetail.html.

    Essa página exibe um único grupo (um blog) e os itens individuais (postagens do blog) que fazem parte do grupo.

  2. Em groupDetail.html, precisamos alterar algumas linhas no elemento DIV que tem um nome de classe item-info. Altere estas linhas:

    
    <h6 class="item-subtitle win-type-ellipsis"
        data-win-bind="textContent: subtitle"></h6>
    <h4 class="item-description" 
        data-win-bind="textContent: description"></h4>
    

    para estas:

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: author"></h6>
    <h4 class="item-description" 
        data-win-bind="textContent: pubDate"></h4>
    

    Em groupDetail.html, o modelo de cabeçalho descreve informações de grupo, e não itens individuais. Portanto, não precisamos modificar a propriedade subtitle. Este é o modelo de cabeçalho:

    
    <div class="headertemplate" data-win-control="WinJS.Binding.Template">
        <h2 class="group-subtitle" data-win-bind="textContent: subtitle"></h2>
        <img class="group-image" src="#" 
            data-win-bind="src: backgroundImage; alt: title" />
        <h4 class="group-description" data-win-bind="innerHTML: description"></h4>
    </div>
    
  3. Entretanto, não temos uma propriedade description para cada grupo (temos essa propriedade para itens) e, por isso, precisamos alterar essa propriedade para updated no código anterior, conforme ilustrado aqui:

    <h4 class="group-description" data-win-bind="innerHTML: updated"></h4>
    
  4. Abra groupedItems.html, que exibe todos os grupos e suas postagens individuais no blog.

  5. Nessa página, o modelo de item WinJS genérico mostra itens individuais (postagens de blog), portanto, é preciso atualizar a propriedade subtitle. Faça esta alteração:

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: subtitle"></h6>
    

    para isto:

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: author"></h6>
    
  6. Salve o projeto e pressione F5 para depurar o aplicativo.

    Você vê o título da página imediatamente, mas há um pequeno atraso enquanto os dados do feed são recuperados. Quando os dados forem retornados e tudo estiver pronto , você verá os itens de cada blog na home page. Clique no cabeçalho de um grupo para ver a página do grupo ou clique em um item para ver uma postagem individual no blog.

Listagem de códigos de data.js

Aqui está a listagem completa de códigos de data.js. O mesmo arquivo data.js é usado para os exemplos de modelo Grade e Dividido, mostrados anteriormente. Para obter o arquivo data.js do modelo Hub/Pivot, veja Leitor da Web JSON que utiliza o modelo Hub/Pivot. Para obter o arquivo data.js do modelo Hub, veja Leitor da Web JSON que utiliza o modelo Hub.


(function () {
    "use strict";

    
    var lightGray = "data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
    var mediumGray = "data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";


    var dataPromises = [];
    var blogs;

    var blogPosts = new WinJS.Binding.List();

    var list = getBlogPosts();
    var groupedItems = list.createGrouped(
        function groupKeySelector(item) { return item.group.key; },
        function groupDataSelector(item) { return item.group; }
    );

    WinJS.Namespace.define("Data", {
        items: groupedItems,
        groups: groupedItems.groups,
        getItemReference: getItemReference,
        getItemsFromGroup: getItemsFromGroup,
        resolveGroupReference: resolveGroupReference,
        resolveItemReference: resolveItemReference
    });

    // Get a reference for an item, using the group key and item title as a
    // unique reference to the item that can be easily serialized.
    function getItemReference(item) {
        return [item.group.key, item.title];
    }

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

    // Get the unique group corresponding to the provided group key.
    function resolveGroupReference(key) {
        return groupedItems.groups.getItemFromKey(key).data;
    }

    // Get a unique item from the provided string array, which should contain a
    // group key and an item title.
    function resolveItemReference(reference) {
        for (var i = 0; i < groupedItems.length; i++) {
            var item = groupedItems.getAt(i);
            if (item.group.key === reference[0] && item.title === reference[1]) {
                return item;
            }
        }
    }



    function getFeeds() {
        // Create an object for each feed.
        blogs = [
            {
                key: "blog1", url:
           'https://windowsteamblog.com/windows/b/developers/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "blog2", url:
           'https://windowsteamblog.com/windows/b/windowsexperience/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            }]
        // Get the content for each feed in the blog's array.
        blogs.forEach(function (feed) {
            feed.dataPromise = feed.acquireSyndication(feed.url);
            dataPromises.push(feed.dataPromise);
        });

        // Return when all asynchronous operations are complete
        return WinJS.Promise.join(dataPromises).then(function () {
            return blogs;
        });

    };

    function acquireSyndication(url) {
        return WinJS.xhr({
            url: url,
            headers: { "If-Modified-Since": "Mon, 27 Mar 1972 00:00:00 GMT" }
        });
    }

    function getBlogPosts() {
        getFeeds().then(function () {
            // Process each blog.
            blogs.forEach(function (feed) {
                feed.dataPromise.then(function (articlesResponse) {
                    var articleSyndication = articlesResponse.responseXML;

                    if (articleSyndication) {
                        // Get the blog title and last updated date.
                        feed.title = articleSyndication.querySelector(
                            "feed > title").textContent;
                        var ds = articleSyndication.querySelector(
                            "feed > updated").textContent;
                        var date = ds.substring(5, 7) + "-" +
                            ds.substring(8, 10) + "-" + ds.substring(0, 4);
                        feed.updated = "Last updated " + date;
                        // Process the blog posts.
                        getItemsFromXml(articleSyndication, blogPosts, feed);
                    }
                    else {
                        // There was an error loading the blog. 
                        feed.title = "Error loading blog";
                        feed.updated = "Error";
                        blogPosts.push({
                            group: feed,
                            key: "Error loading blog",
                            title: feed.url,
                            author: "Unknown",
                            month: "?",
                            day: "?",
                            year: "?",
                            content: "Unable to load the blog at " + feed.url
                        });
                    }
                });
            });
        });

        return blogPosts;
    }

    function getItemsFromXml(articleSyndication, blogPosts, feed) {
        var posts = articleSyndication.querySelectorAll("entry");
        // Process each blog post.
        for (var postIndex = 0; postIndex < posts.length; postIndex++) {
            var post = posts[postIndex];
            // Get the title, author, and date published.
            var postTitle = post.querySelector("title").textContent;
            var postAuthor = post.querySelector("author > name").textContent;
            var pds = post.querySelector("published").textContent;
            var postDate = pds.substring(5, 7) + "-" + pds.substring(8, 10)
                + "-" + pds.substring(0, 4);
            // Process the content so that it displays nicely.
            var staticContent = toStaticHTML(post.querySelector(
                "content").textContent);
            // Store the post info we care about in the array.
            blogPosts.push({
                group: feed, key: feed.title, title: postTitle,
                author: postAuthor, pubDate: postDate,
                backgroundImage: mediumGray, content: staticContent
            });
        }
    }

})();

Tópicos relacionados

Modelos de projetos JavaScript

Modelos de itens JavaScript

Adicionando dados a um modelo de projeto (C#, VB e C++)