【问题标题】:Use previous item in foreach knockout binding在 foreach 淘汰赛绑定中使用上一个项目
【发布时间】:2014-05-22 02:21:00
【问题描述】:

我有以下问题:我有一个可观察数组(从服务器填充),如下所示:

this.elems = ko.observableArray([
    {n: 1, t : 'hello'},
    {n: 1, t : 'why'},
    {n: 1, t : 'are'},
    {n: 2, t : 'some'},
    {n: 2, t : 'ducks'},
    {n: 3, t : 'here'},
    {n: 8, t : '?'}
]);

我想用下面的方式展示它:

      1
Hello
why
are
      2
some
ducks
      3
here
      8
?

如您所见,仅当前一个数字与当前数字不同时,才会显示该数字。 使用foreach 绑定(这是我的jsFiddle)将非常容易。

<div data-bind="foreach: elems">
    <div class="t1">
        <span data-bind="text: n" class="c1"></span>
        <span data-bind="text: t" class="c2"></span>
    </div>
</div>

只有当我能够访问前一个元素时。 我知道我可以修改我的 observalbe 数组并实现我想要的,但是有没有办法在不改变它的情况下做到这一点?

【问题讨论】:

  • 你应该做的是,在你的视图模型上,创建一个计算的 observable 来执行分组。否则你最终会很难测试它。
  • 谢谢大家。

标签: knockout.js


【解决方案1】:

您可以访问 $index 和 $parent 值。试试这个:

<div data-bind="foreach: elems">
    <div class="t1">
        <!-- ko if: $index() === 0 || $parent.elems()[$index() - 1].n !== n -->
        <span data-bind="text: n" class="c1"></span>
        <!-- /ko -->
        <span data-bind="text: t" class="c2"></span>
    </div>
</div>

使用可见绑定的替代方案:

<div data-bind="foreach: elems">
    <div class="t1">
        <span data-bind="text: n, visible: $index() === 0 || $parent.elems()[$index() - 1].n !== n" class="c1"></span>
        <span data-bind="text: t" class="c2"></span>
    </div>
</div>

【讨论】:

  • 啊,在发布我自己的答案之前没有看到你的答案。 +1
【解决方案2】:

如果elems 属性是动态加载的,我建议您使用computed observable 对数据进行分组并返回一个包含组的数组。

所以,给定以下简单的分组函数:

function groupArray(array, keyRetrieverFunc){
    var groupedArray = array.reduce(function(previous, item){
        var key = keyRetrieverFunc(item);
        if (previous[key]){
            previous[key].items.push(item);
        } else {
            previous[key] = { key: key, items: [
                item
            ]};
        }
        return previous;
    }, {});
    return groupedArray
}

我们可以创建一个如下所示的视图模型:

function ViewModel(){
    var self = this;

    self.elems = ko.observableArray([
        {n: 1, t : 'hello'},
        {n: 1, t : 'why'},
        {n: 1, t : 'are'},
        {n: 2, t : 'some'},
        {n: 2, t : 'ducks'},
        {n: 3, t : 'here'},
        {n: 8, t : '?'}
    ]);
    self.groupedElements = ko.computed(function(){
        var groups = {};
        var elements = self.elems();
        var groups = groupArray(elements, function(item){return item.n;});
        var results = [];
        for(var property in groups){
            results.push(groups[property]);
        }
        return results;
    });
}

观察 groupedElements computed observable。这是我们将绑定 DOM 元素的 observable。

<div data-bind="foreach: groupedElements">
    Group name: <span data-bind="text: key"></span>
    <div data-bind="foreach: items">
        <div data-bind="text: t"></div>
    </div>
</div>

当新数据进入并替换观察到的 self.elems 数组时,groupedElements 将自动更新,因为 computed 可观察对象已订阅 self.elems 数组中的更改。

我有他的设置在小提琴http://jsfiddle.net/J6k54/

【讨论】:

    【解决方案3】:

    A.您必须更改视图模型的结构 喜欢:

    function AppViewModel() {
    this.elems = ko.observable([
        {n: 1, t : ['hello','why']},
        {n: 2, t : ['why','not']},
    ]);
    

    }

    ko.applyBindings(new AppViewModel());
    

    B.你的 html 绑定将是:

    <div data-bind="foreach: elems">
    <div class="t1" >
        <span data-bind="text: n" class="c1"></span>
        <span data-bind="foreach: t">
            <br/>
            <span data-bind="text: $data" class="c2"></span>
        </span>
    </div>
    

    【讨论】:

    • 感谢您的回答,但在我的问题中我提到我知道如何做到这一点,但我目前正在寻找不需要更改架构的解决方案。
    • 好的,那么您可以循环访问服务器数据并创建新的 js 对象进行绑定
    【解决方案4】:

    我想你正在寻找这个:

    <div data-bind="foreach: elems">
        <div class="t1">
            <!-- ko if: ($index() === 0 
               || ($parent.elems()[$index()-1].n != $parent.elems()[$index()].n)) -->
            <span data-bind="text: n" class="c1"></span>
            <!--/ko-->
            <span data-bind="text: t" class="c2"></span>
        </div>
    </div>
    

    fiddle

    【讨论】:

      【解决方案5】:

      实现这一点的最简单方法是使用 underscore.js 转换您的数据结构

      看到这个小提琴 http://jsfiddle.net/62Fz8/9/

      underscore.js 中的转换功能真的很简单:

      _.chain(self.elems()) .groupBy(function (o) { return o.n; }) .map(function (o, key) { return { n: key,t: o };}).value();

      只需将此函数包装在 ko.computed 函数中并直接绑定到它。 这会将您的数组变成一个简单的分组,您只需要以下数据绑定:

      <h1> What I you want to achieve </h1>
      <div data-bind="foreach: groupedItems">
        <div class="t1"> 
              <span data-bind="text: n" class="c1"></span>
             <!--ko foreach:t -->
             <span data-bind="text: t" class="c2"></span>
             <!-- /ko -->
      </div>
      </div>
      

      【讨论】:

        猜你喜欢
        • 2013-08-03
        • 1970-01-01
        • 2013-03-14
        • 2020-05-30
        • 2014-01-10
        • 1970-01-01
        • 1970-01-01
        • 2014-12-08
        • 2019-07-25
        相关资源
        最近更新 更多