Share via


Visual Studio 템플릿 데이터를 사용자 지정하는 방법(HTML)

[ 이 문서는 Windows 런타임 앱을 작성하는 Windows에서 8.x 및 Windows Phone 8.x 개발자를 대상으로 합니다. Windows 10용으로 개발하는 경우에는 최신 설명서를 참조하세요.]

허브/피벗, 허브, 피벗, 표 형태 및 분할 템플릿에서 앱에 필요한 데이터를 가져오는 코드는 data.js 파일에 있습니다. 이 파일은 앱에 대한 샘플 데이터 원본을 나타냅니다.data.js 파일에는 일반적으로 동적 데이터로 바꾸기 위해 필요한 정적 데이터가 포함되어 있습니다. 예를 들어 앱이 RSS 또는 JSON 데이터를 가져오도록 xhr 요청을 만들 경우 이 코드를 data.js에 추가할 수 있습니다. 여기에 이 코드를 포함하면 템플릿에 있는 데이터 모델을 변경하지 않고 사용자 데이터를 쉽게 사용할 수 있습니다.

  또한 허브/피벗, 허브 및 피벗 템플릿은 세계화를 지원하는 .resjson 파일에서 정적 데이터를 검색합니다. 자세한 내용은 허브/피벗, 허브 및 피벗 템플릿에서 UI에 대한 데이터 바인딩 예를 참조하세요.

 

앱에 사용자 데이터를 추가할 때 다음과 같은 몇 가지 사항에 유의해야 합니다.

  • 그룹과 항목은 본질적으로 연결되어 있습니다. 앱은 항목 데이터를 그룹으로 구성할 것으로 기대합니다. 사용자 구현에서 그룹과 항목의 연결을 해제할 수 있지만 구현이 작동하려면 코드를 수정해야 합니다. 이 항목에서는 템플릿 데이터 모델에서 그룹을 사용하는 방법을 보여 줍니다.
  • data.js에서 앱에 대한 사용자 지정 데이터를 구현하는 경우 사용자 지정 데이터에 고유한 속성 이름이 템플릿에 사용되는 속성 이름에 매핑되는지 확인해야 합니다. 템플릿에 사용되는 이름을 변경할 수 있지만 그렇게 하려면 코드를 수정해야 합니다. 이 항목에서는 코드를 수정하는 방법을 예를 들어 보여 줍니다.

항목 및 그룹

템플릿 데이터는 WinJS.Binding.List에 저장됩니다. 다음 코드는 data.js 파일의 목록 선언을 표시합니다.

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

아래와 같이 항목 데이터 배열(이 예제의 sampleItems)이 push 함수에 의해 WinJS.Binding.List에 전달됩니다.

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

앱에서 사용자 지정 데이터를 수정할 때 동일한 데이터 그룹화 패턴을 따를 수 있습니다. 크기가 작은 데이터 집합의 경우 ListView에 대해 WinJS.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;
    });
}

  createFiltered를 호출하는 getItemsFromGroup과 같은 함수가 WinJS.Binding.List의 새 프로젝션을 생성함으로 사용자가 페이지에서 이동해 나가는 경우 반환된 개체를 삭제해야 할 수도 있습니다. 개체를 삭제하려면WinJS.Binding.List.dispose 메서드를 호출합니다.

 

JavaScript용 Windows Library 함수인 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 속성에 할당됩니다.

템플릿에서 데이터는 일반적으로 각 HTML 페이지에 연결된 .js 파일에 정의되어 있는 init 함수나 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.Binding.Template을 기반으로 하는 WinJS 템플릿은 여러 데이터 인스턴스를 형식 지정하고 표시하는 데 사용됩니다. 그리드 및 분할 템플릿에서 사용되는 가장 일반적인 템플릿은 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 코드 참조가 데이터에 사용된 속성 이름과 일치하도록 수정합니다. 템플릿에서 사용되는 속성은 다음과 같습니다.
    • title, subtitle, descriptionbackgroundImage(그룹 및 항목 속성)
    • groupcontent(항목 속성)
    • key(그룹 속성)

동일한 WinJS 템플릿 패턴에 따라 그리드 앱 템플릿은 일부 HTML 페이지에서 headerTemplate을 사용하기도 합니다.

허브/피벗, 허브 및 피벗 템플릿에서 UI에 대한 데이터 바인딩 예

Visual Studio의 허브/피벗, 허브 및 피벗 프로젝트 템플릿은 두 가지 데이터 원본을 구현하는 방법을 보여줍니다.

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

    // . . .   

},

뒤로 단추를 사용하여 페이지로 이동하는 경우 새 데이터를 대기할 필요가 없으므로 페이지의 초기화 함수에서 직접 데이터 바인딩 함수가 호출됩니다.

  허브 템플릿 코드에서 _section3lv에 저장된 ListView 요소의 DOM을 쿼리하기 위해 앱은 Hub 컨트롤의 loadingstatechanged 이벤트 처리기에서 _hubReady 함수를 호출합니다. 이 이벤트는 허브 페이지 로드가 완료된 경우에만 활성화됩니다. 이 이벤트 처리기를 사용하면 DOM을 쿼리하여 ListView와 연결된 중첩 DIV 요소를 가져올 수 있습니다.

 

허브/피벗 및 허브 템플릿에서 비동기 데이터가 작동하도록 만들기 위한 전체 코드는 허브/피벗 템플릿을 사용하는 JSON 웹 뷰어허브 템플릿을 사용하는 JSON 웹 뷰어를 참조하세요. 여기에 설명된 사용자 지정 외에 샘플 앱을 다음과 같이 변경했습니다.

  • xhr 요청을 사용하여 데이터를 검색하고 JSON 데이터(Flickr)를 구문 분석하는 코드를 데이터 모델(data.js)에 포함했습니다.
  • 여러 데이터 요청을 처리하고 데이터가 반환될 때 dataReady 이벤트를 활성화하는 코드를 데이터 모델에 포함했습니다.
  • 새 데이터를 요청하기 위해 입력 상자를 UI에 포함했습니다.
  • 데이터 요청의 상태를 표시하기 위해 진행률 표시줄을 포함 했습니다.
  • 입력 상자 및 진행률 표시줄에 대해 CSS 스타일을 추가했습니다.
  • _hubReady 또는 _hubReadyPhone 등과 같은 Hub 컨트롤이 완전히 로드된 후 페이지를 초기화하는 함수를 포함했습니다.
  • 클릭 이벤트를 지원하도록 허브/피벗 또는 허브의 <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 배열을 포함하는 generateSampleData 함수를 제거합니다.

    이 데이터를 RSS 데이터로 바꿀 것입니다. groupDescription과 같은 대부분의 자리 표시자 변수는 사용하지 않겠지만, 새 코드의 작동을 위해 자리 표시자 이미지, lightGraymediumGray를 다시 사용할 것입니다.

  4. generateSampleData를 제거한 동일한 위치에서 다음 코드를 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. 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; }
    );
    

    그룹화—groupKeySelectorgroupDataSelector 함수를 지정하는 코드를 createGrouped에서 다시 사용합니다.

    템플릿에 사용된 일부 속성 이름을 변경했기 때문에 HTML 페이지를 업데이트해야 합니다. 특히, 항목(그룹 아님)을 참조하는 모든 subtitle 속성에 대해 subtitle author로 변경합니다. 항목을 참조하는 모든 description 속성에 대해 description pubDate로 변경해야 합니다.

    UI에서 이러한 변경을 구현하려면 다음 섹션 중 하나를 참조하세요.

    • Split 템플릿의 UI에 예제 데이터 바인딩
    • Grid 템플릿의 UI에 예제 데이터 바인딩

Split 템플릿의 UI에 예제 데이터 바인딩

  1. Split 템플릿에서 예제 코드를 사용하려면 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 키를 눌러서 앱을 디버그합니다.

    페이지 제목이 바로 표시되지만 피드 데이터를 검색하는 동안 약간의 지연이 있습니다. 모든 약속이 이행되면 홈페이지에 각 블로그가 표시됩니다. 블로그 중 하나를 클릭하여 블로그 게시물을 마스터/자세히 보기로 봅니다.

Grid 템플릿의 UI에 예제 데이터 바인딩

이러한 단계를 수행하기 전에 UI에 대한 데이터 바인딩 예에 설명된 대로 data.js 프로젝트 파일을 업데이트합니다.

  1. Grid 템플릿에서 RSS 예제 코드를 사용하려면 groupDetail.html을 엽니다.

    이 페이지에는 단일 그룹(블로그)과 그룹의 일부인 개별 항목(블로그 게시물)이 표시됩니다.

  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 웹 뷰어를 참조하세요. 허브 템플릿용 data.js 파일은 허브 템플릿을 사용하는 JSON 웹 뷰어를 참조하세요.


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

})();

관련 항목

JavaScript 프로젝트 템플릿

JavaScript 항목 템플릿

프로젝트 템플릿에 데이터 추가(C#, VB 및 C++)