Visual Studio のテンプレート データをカスタマイズする方法 (HTML)

[ この記事は、Windows ランタイム アプリを作成する Windows 8.x および Windows Phone 8.x 開発者を対象としています。Windows 10 向けの開発を行っている場合は、「最新のドキュメント」をご覧ください]

ハブ/ピボット、ハブ、ピボット、グリッド、スプリットの各テンプレートでは、アプリに必要なデータを取得するためのコードは data.js ファイルに含まれています。 このファイルは、アプリのサンプル データ ソースを表しています。data.js ファイルに含まれている静的データは、通常、動的データに置き換える必要があります。たとえば、アプリで単一の xhr 要求を行って RSS データまたは JSON データを取得する場合、そのコードを data.js に含める必要があります。このファイルにコードを含めると、テンプレートにあるデータ モデルを変更せずに、自分のデータを簡単に使うことができます。

ヒント  また、ハブ/ピボット、ハブ、ピボットの各テンプレートでは、グローバリゼーションをサポートする .resjson ファイルから静的データを取得します。詳しくは、「ハブ/ピボット、ハブ、ピボットのテンプレートの UI にデータをバインドする例」をご覧ください。

 

アプリに自分のデータを追加する際には、次の点にご注意ください。

  • グループと項目が完全にリンクしていること。アプリでは、項目データがグループにまとめられていることを想定しています。独自の実装でデータと項目をリンクしないこともできますが、その場合はコードの変更が必要になります。このトピックでは、テンプレート データ モデルでグループを使う方法について説明します。
  • アプリ用のカスタム データを data.js に実装する際、そのカスタム データに固有のプロパティ名が、テンプレートで使われているプロパティ名にマップされていることを確認する必要があります。テンプレートで使われているプロパティ名を変更することもできますが、これにはさらにコードの修正が必要になります。このトピックでは、その方法の例を示します。

項目とグループ

テンプレート データは WinJS.Binding.List に保存されます。次のコードは、data.js ファイルでの一覧の宣言を示しています。

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

WinJS.Binding.List に項目データの配列 (この例では sampleItems) を渡すには、次のように、push 関数を使います。

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

WinJS.Binding.List には、データのグループ化を処理する内部ロジックが含まれています。sampleItems 配列には、group プロパティが含まれており、項目が属しているグループを識別します (サンプル データの場合は、グループは sampleGroups 配列に指定されています)。generateSampleData 関数の項目データの配列を次に示します。

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

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

    return sampleItems;
}

アプリをカスタム データ用に変更する際は、データのグループ化に同じパターンを使う場合があります。データ セットが小さい場合は、ListViewWinJS.Binding.List を使うことをお勧めします。項目をグループ化しなくても WinJS.Binding.List は使えますが、テンプレートでグループ ベースのデータが必要となる場所では、テンプレート コードを変更する必要があります。

ヒント  WinJS.Binding.List は、JavaScript 配列を使う同期データ ソースです。項目数が数千個になりうる非常に大きなデータ セットの場合は、非同期データ ソースを使う必要があります。詳しくは、「ListView の使用」をご覧ください。

 

WinJS.Binding.ListcreateGrouped 関数では、グループ キーと項目グループの値を使って項目をグループ化する方法を指定します。この関数は data.js で呼び出されます。keygroup は、どちらもサンプルのデータ配列で指定されるプロパティ名です。

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

テンプレート アプリに項目の一覧が必要な場合、getItemsFromGroup を呼び出します。これにより、指定したグループに属する項目のみを含む WinJS.Binding.List が返されます。

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

ヒント  getItemsFromGroup など、createFiltered を呼び出す関数は、WinJS.Binding.List の新しいプロジェクションを作成します。ページから移動する場合、返されたオブジェクトを破棄することが必要になる場合があります。オブジェクトを破棄するには、WinJS.Binding.List.dispose メソッドを呼び出します。

 

JavaScript 用 Windows ライブラリの define 関数では、一連のパブリック メンバー関数と一緒に Data という名前の名前空間を指定することで、アプリで使うデータを公開します。

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

アプリ内のページごとに別々のデータ ソースを定義する場合や、別のデータ モデルを定義する場合は、JavaScript コード内のこれらのメンバーへの呼び出しをすべて置き換える必要があります。

UI へのグループと項目のデータのバインド

次のコードは、ListView コントロールのマークアップの例を示しています。ListView のデータ ソースは、次に示すように、itemDataSource プロパティに指定されています。この例は、分割テンプレートの split.html からの抜粋です。


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

上記のコードで、ページに関連付けられた itemDataSource プロパティは、ListView コントロールの itemDataSource プロパティに割り当てられます。

テンプレートのデータは、通常、init 関数か、各 HTML ページに関連付けられた .js ファイルで定義された ready 関数で UI にバインドされます。次のコードは、split.html の init 関数に含まれています。このコードで、アプリは、グループ参照を取得し、data.js に実装されている getItemsFromGroup を呼び出します。既に説明したとおり、getItemsFromGroup では、指定したグループの項目のみを含む WinJS.Binding.List が返されます。

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

次に、getItemsFromGroup から返された一覧をページの itemDataSource プロパティにバインドします。これにより、データが ListView にバインドされます。さらに、項目の選択 (_selectionChanged) のハンドラーを指定します。


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

それぞれの項目を ListView に表示するために、アプリは、次に示すように、テンプレートを ListView に関連付けます。このコードは ListView コントロールのマークアップに含まれ、itemTemplate プロパティを使って、クラス名が itemtemplate の DIV 要素を指定します。

itemTemplate: select('.itemtemplate')

WinJS テンプレートは、WinJS.Binding.Template に基づいており、データの複数のインスタンスの書式設定と表示に使われます。グリッド テンプレートと分割テンプレートで最もよく使われるテンプレートは、ListView で項目を表示するための項目テンプレートです。すべての WinJS のテンプレート オブジェクトと同じように、項目テンプレートを宣言するには、data-win-control 属性を追加して WinJS.Binding.Template に設定します。split.html の itemtemplate の 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 は、任意の ListView 項目に使われます。ListView 項目は、コンテキストに応じて、グループまたは個々のデータ項目となります。たとえば、items.html では、ListView 項目はグループです。

重要  WinJS.Binding.Template を使って作るテンプレートは、Visual Studio プロジェクト テンプレートとグリッドやスプリットなどの項目テンプレートには関連しません。

 

プロジェクト テンプレートではデータに特定のプロパティが存在することを想定しており、HTML ではこれらのプロパティに明示的に名前が付けられます。上に示した itemtemplate の HTML コードでは、titlesubtitle などのプロパティを見つけることができます。カスタム アプリのデータでこれらのプロパティ名を使わない場合は、次のいずれかを行う必要があります。

  • 自分のデータを (通常は data.js 内の) これらのプロパティ名にマップする
  • テンプレート コードでこれらのプロパティへの HTML と .js のコード参照をすべて修正し、自分のデータで使われているプロパティ名と一致するようにするテンプレートで使うプロパティには、次のものがあります。
    • titlesubtitledescriptionbackgroundImage (グループや項目のプロパティ)
    • groupcontent (項目のプロパティ)
    • key (グループのプロパティ)

同じ WinJS のテンプレート パターンに従い、グリッド アプリ テンプレートでは、その HTML ページのいくつかで headerTemplate も使います。

ハブ/ピボット、ハブ、ピボットのテンプレートの UI にデータをバインドする例

Visual Studio のハブ/ピボット、ハブ、ピボットの各プロジェクト テンプレートには、次の 2 つの異なるデータ ソースを実装する方法が紹介されています。

  • .resjson リソース ファイルに格納されているグローバルな静的データ。このデータは、いくつかのアプリ セクション (PivotItem コントロールや HubSection コントロール) で使います。
  • データ モデルを表す data.js のサンプル データ。このファイルは、グリッド テンプレートや分割テンプレートにあるものと同じです。このサンプル データは、いずれかのアプリ セクションの ListView コントロールで使います。

HTML の宣言型関数を使って、最初にサンプル データを取得します。データ モデルは、既定で同期されます。すべてのセクションで動的データを使うようにテンプレートをカスタマイズするには、hub.html や hub.js などのファイルを一部変更する必要があります。次のサンプル アプリでは、非同期データをサポートするようにハブ/ピボット テンプレートとハブ テンプレートをカスタマイズしています。

.resjson ファイル内のグローバルなデータを置き換えるのは簡単なため、サンプル アプリではこのリソース ファイルを変更しません。サンプル アプリでは、ハブ/ピボット セクションにある <img> 要素と ListView コントロールのデータは、非同期的に取得されます。

.resjson ファイルのグローバルなデータの提供について詳しくは、「クイック スタート: UI リソースの翻訳」をご覧ください。

ハブ/ピボットの ListView コントロールへの非同期データのバインドをサポートするには、まずデータ モデルを呼び出す hub.js のグローバル変数を置き換えます。

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

次の変数宣言に置き換えます。


var section3Group = "group2";
var section3Items;

さらに、hub.js の宣言型関数の実装を変更する必要があります。既定のテンプレートの実装では、これらの関数は、既に利用可能なデータ (たとえば、section3Items.dataSource 呼び出し) に依存します。次のコードを置き換えます。

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

上のコード行を次のコード行と置き換えます。


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

このコードでは、準備が完了する前にデータをバインドすることがないように、section3DataSource 関数を null に設定しています。データ ソースについては、後でデータ バインディング関数内で設定します。この関数は、サンプル アプリに応じて、_bindData または bindListView になります。

データ バインディング関数は、データが利用可能になると呼び出されます。データ バインディング関数を使うために、data.js 内のサンプル アプリで定義されているデータ モデルの dataReady イベント用リスナーを追加します。


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

アプリは、onDataCompleted イベント ハンドラー (ここには示されていません) からデータ バインディング関数を呼び出します。ハブ テンプレートのサンプルの _bindData 関数のコードを次に示します。このコードでは、ListViewitemDataSource プロパティを設定しています。


_bindData: function (context, grp1Items, grp2Items) {

    var self = context;

    // . . .

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

    // . . .   

},

戻るボタンを使ってページを移動する場合は、新しいデータを待機する必要がないため、データ バインディング関数がページの初期化関数から直接呼び出されます。

ヒント  ハブ テンプレートのコードでは、DOM に対して (_section3lv に保存されている) ListView 要素を照会するために、アプリは、ハブ コントロールの loadingstatechanged イベント ハンドラーから _hubReady 関数を呼び出します。このイベントは、ハブ ページの読み込みが完了したときだけアクティブ化されます。このイベント ハンドラーを使うと、DOM に対して照会を行って、ListView に関連付けられている入れ子になった DIV 要素を取得でいます。

 

ハブ/ピボット テンプレートとハブ テンプレートで非同期データを操作する完全なコードについては、ハブ/ピボット テンプレートを使った JSON Web リーダーに関するページハブ テンプレートを使った JSON Web リーダーに関するページをご覧ください。ここで説明したカスタマイズに加えて、サンプル アプリには次のような変更が加えられています。

  • xhr 要求を使ってデータを取得し、(Flickr からの) JSON データを分析するためのコードをデータ モデル (data.js) に追加しました。
  • 複数のデータ要求を処理し、データが返されたときに dataReady イベントをアクティブ化するためのコードをデータ モデルに追加しました。
  • 新しいデータを要求するための入力ボックスを UI に追加しました。
  • データ要求の状態を示すための進行状況バーを追加しました。
  • 入力ボックスと進行状況バー用の CSS スタイルを追加しました。
  • ハブ コントロールが完全に読み込まれた後にページを初期化するための関数 (_hubReady_hubReadyPhone など) を追加しました。
  • クリック イベントをサポートするように、ハブ/ピボットまたはハブの <img> 要素を変更しました (変更されたファイルはテンプレート固有のファイルです)。
  • 非同期データをハブ/ピボットまたはハブの <img> 要素にバインドするように、ファイルを変更しました (変更されたファイルはテンプレート固有のファイルです)。
  • ハブの <img> 要素から画像へのナビゲーションをサポートするように、hub.js を変更しました (変更されたファイルはテンプレート固有のファイルです)。
  • 単一の画像の表示をサポートするために item.html と item.js を変更しました。

UI へのデータのバインドの例 (グリッドと分割)

このセクションでは、自分のデータ ソースをグリッドとスプリットの各プロジェクト テンプレートに実装する方法を説明します。このサンプル コードでは、xhr 要求を使って RSS データを生成します。

重要  ハブ テンプレートで非同期データを実装するには、「ハブ テンプレートでの UI へのデータのバインド」をご覧ください。

 

data.js の更新

  1. Visual Studio で新しいプロジェクトを作成します。スプリット アプリ プロジェクト テンプレートまたはグリッド アプリ プロジェクト テンプレートを使います。

  2. data.js ファイルの先頭近くにある use strict ステートメントの後に次の変数を追加します。

    var lightGray = "data:image/png;base64,
        iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY7h4+cp/AAhpA3h+ANDKAAAAAElFTkSuQmCC";
    var mediumGray = "data:image/png;base64,
        iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXY5g8dcZ/AAY/AsAlWFQ+AAAAAElFTkSuQmCC";
    
  3. data.js で、sampleGroupssampleItems の 2 つの配列を含む generateSampleData 関数を削除します。

    このデータを RSS データに置き換えます。groupDescription などのプレースホルダーの変数のほとんどは使いませんが、新しいコードを動作させるために、lightGraymediumGray のプレースホルダーの画像を再利用します。

  4. data.js の generateSampleData を削除した場所に次のコードを追加します。

    
    function getFeeds() {
        // Create an object for each feed.
        blogs = [
            {
                key: "blog1", url: 
           'http://windowsteamblog.com/windows/b/developers/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "blog2", url: 
           'http://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. data.js で、次のコードを見つけます。

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

    上のコード行を次のコード行と置き換えます。

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

    グループ化を指定する createGrouped のコード、groupKeySelector 関数と groupDataSelector 関数をもう一度使います。

    テンプレートで使われているプロパティ名を一部変更したため、HTML ページでいくつか更新する必要があります。特に、(グループではなく) 項目を参照するすべての subtitle プロパティについて、subtitleauthor に変更する必要があります。項目を参照するすべての description プロパティについて、descriptionpubDate に変更する必要があります。

    これらの変更を UI に実装するには、次のいずれかのセクションをご覧ください。

    • UI へのサンプル データのバインド (スプリット テンプレート)
    • UI へのサンプル データのバインド (グリッド テンプレート)

UI へのサンプル データのバインド (スプリット テンプレート)

  1. スプリット テンプレートでサンプル コードを使うには、split.html を開きます。

  2. split.html で、itemtemplate というクラス名を持つ DIV 要素の数行を変更する必要があります。次の行を変更します。

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

    変更後の行は次のとおりです。

    <h6 class="item-subtitle win-type-ellipsis" data-win-bind="textContent: author"></h6>
    
  3. また、split.html で、記事セクション (articlesection) に含まれているヘッダー情報を更新する必要があります。次の行を変更します。

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

    変更後の行は次のとおりです。

    <h4 class="article-subtitle" data-win-bind="textContent: author"></h4>
    
  4. items.html を開きます。

    HTML コードで定義されている WinJS 項目テンプレートには、任意の ListView 項目が含まれています。items.html で、項目テンプレートはグループ (ブログ) を表示するために使われます。ここで変更する必要があるグループ プロパティは、subtitle だけです。

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: subtitle"></h6>
    
  5. 次に示すように、subtitle プロパティを updated に変更します。

    <h6 class="item-subtitle win-type-ellipsis"
        data-win-bind="textContent: updated"></h6>
    
  6. プロジェクトを保存し、F5 キーを押してアプリをデバッグします。

    ページ タイトルはすぐに表示されますが、フィード データを取得するのに少し時間がかかります。すべての条件が満たされたら、ホーム ページに各ブログが表示されます。いずれかのブログをクリックすると、マスター/詳細ビューにブログ投稿が表示されます。

UI へのサンプル データのバインド (グリッド テンプレート)

次の手順を実行する前に、「UI にデータをバインドする例」に従って data.js プロジェクト ファイルを更新します。

  1. グリッド テンプレートで RSS のサンプル コードを使うには、groupDetail.html を開きます。

    このページには、1 つのグループ (ブログ) と、そのグループに含まれる個々の項目 (ブログ投稿) が表示されます。

  2. groupDetail.html で、item-info というクラス名を持つ DIV 要素の数行を変更する必要があります。次の行を変更します。

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

    変更後の行は次のとおりです。

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

    groupDetail.html で、ヘッダー テンプレートは個別の項目ではなくグループ情報を表します。そのため、subtitle プロパティを変更する必要はありません。ヘッダー テンプレートは次のようになります。

    
    <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. ただし、各グループに対する description プロパティがないため (このプロパティは項目に対して存在します)、上のコードに示されているこのプロパティを、次のように updated に変更する必要があります。

    <h4 class="group-description" data-win-bind="innerHTML: updated"></h4>
    
  4. groupedItems.html を開きます。このページには、すべてのグループと、それらの個々のブログ投稿が表示されます。

  5. このページで、汎用の WinJS 項目テンプレートは個々の項目 (ブログ投稿) を表示します。そのため、subtitle プロパティを更新する必要があります。次の行を変更します。

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

    変更後の行は次のとおりです。

    <h6 class="item-subtitle win-type-ellipsis" 
        data-win-bind="textContent: author"></h6>
    
  6. プロジェクトを保存し、F5 キーを押してアプリをデバッグします。

    ページ タイトルはすぐに表示されますが、フィード データを取得するのに少し時間がかかります。データが返され、すべての条件が満たされると、ホーム ページの各ブログに項目が表示されます。グループのページを表示するにはグループの見出しをクリックし、個々のブログ投稿を表示するには項目をクリックします。

data.js のコードの一覧

data.js のコード一覧を以下に示します。前に示したグリッド テンプレートや分割テンプレートの例と同じ data.js ファイルを使っています。ハブ/ピボット テンプレートの data.js ファイルについては、「ハブ/ピボット テンプレートを使った JSON Web リーダー」をご覧ください。ハブ テンプレートの data.js ファイルについては、「ハブ テンプレートを使った JSON Web リーダー」をご覧ください。


(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:
           'http://windowsteamblog.com/windows/b/developers/atom.aspx',
                title: 'tbd', subtitle: 'subtitle', updated: 'tbd',
                backgroundImage: lightGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "blog2", url:
           'http://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
            });
        }
    }

})();

関連トピック

JavaScript プロジェクト テンプレート

JavaScript 項目テンプレート

プロジェクト テンプレートへのデータの追加 (C#/VB/C++ と XAML を使用)