嵌套 ListView 或嵌套 Repeater

Nested ListView or Nested Repeater

我正在尝试使用 WinJS 4.0 创建嵌套转发器或嵌套列表视图,但我无法弄清楚如何绑定内部 listview/repeater.

的数据源

这是我正在尝试做的事情的示例(请注意,控件可以是 Repeater,我更喜欢它):

HTML:

<div id="myList" data-win-control="WinJS.UI.ListView">
        <span data-win-bind="innerText: title"></span>          
        <div data-win-control="WinJS.UI.ListView">
        <span data-win-bind="innerText: name"></span>            
    </div>
</div>

JS:

var myList = element.querySelector('#myList).winControl;
var myData = [
      {
          title: "line 1",
          items: [
              {name: "item 1.1"},
              {name: "item 1.2"}
          ]
      },
      {
          title: "line 2",
          items: [
              {name: "item 2.1"},
              {name: "item 2.2"}
          ]
      }  
    ];
   myList.data = new WinJS.Binding.List(myData);

当我尝试这个时,内部列表没有呈现任何内容。我曾尝试使用这个答案 Nested Repeaters Using Table Tags and this one WinJS: Nested ListViews 但我似乎仍然遇到同样的问题,希望它不那么复杂(比如 KnockOut)。

我知道有人提到 WinJS 不支持嵌套的 ListView,但这似乎是几年前的事了,我希望这仍然不是问题所在。

更新

由于 Kraig 的回答,我能够使嵌套中继器正常工作。这是我的代码的样子:

HTML:

<div id="myTemplate" data-win-control="WinJS.Binding.Template">
   <div
      <span>Bucket:</span><span data-win-bind="innerText: name"></span>
      <span>Amount:</span><input type="text" data-win-bind="value: amount" />
      <button class="removeBucket">X</button>
      <div id="bucketItems" data-win-control="WinJS.UI.Repeater" 
         data-win-options="{template: select('#myTemplate')}" 
         data-win-bind="winControl.data: lineItems">
      </div>
   </div>
</div>
<div id="budgetBuckets" data-win-control="WinJS.UI.Repeater"
   data-win-options="{data: Data.buckets,template: select('#myTemplate')}">
</div>

JS:(在 "use strict" 语句之后)

WinJS.Namespace.define("Data", {
        buckets: new WinJS.Binding.List([
            {
                name: "A",
                amount: 5,
                lineItems: new WinJS.Binding.List( [
                        { name: 'test item1', amount: 50 },
                        { name: 'test item2', amount: 25 }
                    ]
                )
            }
        ])
    })

*请注意,这回答了我的部分问题,但是,我真的很想在 repo 调用之后执行所有这些操作并以编程方式设置转发器数据源。我将继续为此努力,如果我得到它,我将 post 作为公认的答案。

HTML Repeater control sample for Windows 8.1 has an example in scenario 6 with a nested Repeater, and in this case the Repeater is created through a Template control. That's a good place to start. (I discuss this sample in Chapter 7 of Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition,从第 372 页开始,或嵌套部分的第 374 页。)

应该仍然可以使用 WinJS 4,虽然我还没有尝试过。

好的,所以我必须非常感谢 Kraig,因为他让我走上了解决这个问题的正确道路,而且参考书 Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition 非常棒。

最初的问题是未正确使用模板(在 data-win-bind 属性中使用大括号)、未正确构建我的 HTML 以及未将子列表设置为 WinJS.Binding.List 数据源。下面是仅从代码绑定数据时创建嵌套转发器的最终工作代码结构:

HTML:

这是子列表的模板。它看起来很相似,但我计划添加更多东西,所以我希望它是分开的,而不是像书中提到的那样递归。请注意,模板控件声明后的内部 div 对我来说很重要。

<div id="bucketItemTemplate" data-win-control="WinJS.Binding.Template">
   <div>
      <span>Description:</span>
      <span data-win-bind="innerText: description"></span>
      <span>Amount:</span>
      <input type="text" data-win-bind="value: amount" />
      <button class="removeBucketItem">X</button>
   </div>
</div>

这是列表的主要转发器模板。请注意,模板控件声明后的内部 div 对我来说很重要。另一个关键点是对子列表的 属性 名称使用 "winControl.data" 属性。

<div id="bucketTemplate" data-win-control="WinJS.Binding.Template">
   <div>
      <span>Bucket:</span>
      <span data-win-bind="innerText: bucket"></span>
      <span>Amount:</span>
      <input type="text" data-win-bind="value: amount" />
      <button class="removeBucket">X</button>
      <div id="bucketItems" data-win-control="WinJS.UI.Repeater" 
         data-win-options="{template: select('#bucketItemTemplate')}" 
         data-win-bind="winControl.data: lineItems">
      </div>
   </div>
</div>

这是嵌套转发器的主要控制元素,非常基础。

<div id="budgetBuckets" data-win-control="WinJS.UI.Repeater" 
   data-win-options="{template: select('#bucketTemplate')}">
</div>

JavaScript:

JavaScript 归结为几个简单的步骤:

  1. 获取winControl

    var bucketsControl = element.querySelector('#budgetBuckets').winControl;

  2. 遍历元素并将子列表变成绑定列表 - 这里的数据是编造的,但很容易来自 repo:

    var bucketsData = selectedBudget.buckets; for (var i = 0; i < bucketsData.length; i++) { bucketsData[i].lineItems = new WinJS.Binding.List([{ description: i, amount: i * 10 }]); }

  3. 然后最后把整个数据转化成一个Binding list,设置到winControl的"data"属性

    bucketsControl.data = new WinJS.Binding.List(bucketsData);

*请注意,为清楚起见,这是整个 JavaScript 文件。

(function () {
    "use strict";
    var nav = WinJS.Navigation;

    WinJS.UI.Pages.define("/pages/budget/budget.html", {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.

        ready: function (element, options) {
            // TODO: Initialize the page here.
            var bindableBuckets;
            require(['repository'], function (repo) {
                //we can setup our save button here
                var appBar = document.getElementById('appBarBudget').winControl;
                appBar.getCommandById('cmdSave').addEventListener('click', function () {                    
                    //do save work
                }, false);
                repo.getBudgets(nav.state.budgetSelectedIndex).done(function (selectedBudget) {
                    var budgetContainer = element.querySelector('#budgetContainer');
                    WinJS.Binding.processAll(budgetContainer, selectedBudget);
                    var bucketsControl = element.querySelector('#budgetBuckets').winControl;
                    var bucketsData = selectedBudget.buckets;
                    for (var i = 0; i < bucketsData.length; i++)
                    {
                        bucketsData[i].lineItems = new WinJS.Binding.List([{ description: i, amount: i * 10 }]);
                    }
                    bucketsControl.data = new WinJS.Binding.List(bucketsData);
                });

            });
            WinJS.UI.processAll();

        }
    });
})();