【问题标题】:Combining / Structuring multiple knockout observable arrays组合/构建多个淘汰赛可观察数组
【发布时间】:2018-08-02 13:20:12
【问题描述】:

我的视图模型中有 2 个可观察数组:

self.main = ko.observablearray();
self.sub = ko.observablearry();

Main 加载了一个 getjson 调用,并将 12 个带有描述/排序顺序(即 1-12)的项目返回到 self.main 数组中,sub 将子描述返回给 main。

主要返回的json:

<storedProc_Result>
<ID>4</ID>
<mainDescription>
      foo foo foo
</mainDescription>
<SortOrder>1</SortOrder>
</storedProc_Result>

子返回的json:

<storedProc2_Result>
<SortOrder>1.1</SortOrder>
<ID>21</ID>
<SubDescription>bar bar bar</SubDescription>
</storedProc2_Result>
<storedProc2_Result>
<SortOrder>1.2</SortOrder>
<ID>23</ID>
<SubDescription>bar bar bar</SubDescription>
</storedProc2_Result>

我将如何循环并根据 SortOrder 值组合这两个数组,以便我可以在我的视图页面上执行 foreach 循环? IE。

  • 主要说明 1
    • 子说明 1.1
    • 子说明 1.2
  • 主要说明 2
    • 子说明 2.1
  • ...

【问题讨论】:

    标签: javascript jquery arrays sorting knockout.js


    【解决方案1】:

    1。数据

    让我们首先以更易读的格式探索您提供的数据:

    主要

    {
      ID: 4,
      mainDescription: "foo foo foo",
      SortOrder: "1"
    }
    

    {
      ID: 21,
      SubDescription: "bar bar bar",
      SortOrder: "1.1"
    }
    

    2。视图模型

    从您想要的输出中,我们了解到我们需要:

    AppViewModel

    {
      mains: [ /* MainViewModel */ ]
    }
    

    一个MainViewModel

    { 
      title: "foo foo foo",
      numberLabel: "1",
      subs: [ /* SubViewModel */ ],
    
      // The label as a number
      sortOrder: parseInt("1", 10)
    }
    

    一个SubViewModel

    {
      title: "bar bar bar",
      numberLabel: "1.1",
    
      // We sort by the second number in the label
      sortOrder: parseInt("1.1".split(".")[1], 10),
    
      // We group by the first part of the label
      groupKey: "1.1".split(".")[0]
    }
    

    3。意见

    使用建议的视图模型结构,我们可以创建视图:

    <ul data-bind="foreach: mains">
      <li>
        <p data-bind="text: title + ' ' + numberLabel">
        <ul data-bind="foreach: subs">
          <li data-bind="text: title + ' ' + numberLabel"></li>
        </ul>
      </li>
    </ul>
    

    4。对视图模型实例进行排序

    因为我们有数字 sortKey 属性,我们可以做一个数字比较来排序:

    // Sort utils
    const numericSort = (x, y) => x > y ? 1 : x < y ? -1 : 0;
    const vmSort = (vm1, vm2) => numericSort(vm1.sortKey, vm2.sortKey);
    

    5。分组视图模型

    我们可以通过 groupKey 对 SubViewModel 实例列表进行分组:

    const groupSubs = subs => subs.reduce(
      (gs, s) => Object.assign(
        gs,
        { [s.groupKey]: (gs[s.groupkey] || []).concat(s) }
      ), { }
    )
    

    现在,我们可以使用ko.pureComputed 实例创建一个从数据到应用的良好链。

    const subData = ko.observableArray([]);
    const subVMs = ko.pureComputed(
      () => subData().map(SubViewModel)
    );
    const subGroups = ko.pureComputed(
      () => groupSubs(subVMs())
    );
    
    const mainData = ko.observableArray([]);
    const mainVMs = ko.pureComputed(
      () => mainData().map(m => MainViewModel(m, subGroups))
    );
    
    ko.applyBindings(AppViewModel(mainVMs));
    

    工作示例

    这个流程在一个工作示例中说明:

    const mains = ko.observableArray([]);
    const subs = ko.observableArray([]);
    
    const subGroup = sub => sub.sortOrder.split(".")[0]
    
    const subsByMain = ko.pureComputed(() =>
      subs()
        .map(sub => [subGroup(sub), sub])
        .reduce(
          (groups, [id, sub]) => Object.assign(
            groups, { [id]: (groups[id] || []).concat(sub) }  
          ), {}
        )
    );
    
    const Main = function(config, groups) {
      this.title = config.description;
      this.sortOrder = config.sortOrder;
      
      this.subs = ko.pureComputed(() => 
        groups()[config.sortOrder] || []
      );
    };
    
    ko.applyBindings({ 
      mains: ko.pureComputed(() => 
        mains().map(cfg => new Main(cfg, subsByMain))
      )
    });
    
    
    const getMainData = cb => setTimeout(() => cb([
      { id: 1, description: "foo foo foo", sortOrder: "1" },
      { id: 2, description: "bar bar bar", sortOrder: "2" }
    ]), 500);
    
    const getSubData = cb => setTimeout(() => cb([
      { id: 3, description: "foo 1", sortOrder: "1.1" },
      { id: 4, description: "foo 2", sortOrder: "1.2" },
      { id: 5, description: "bar 1", sortOrder: "2.1" },
      { id: 6, description: "bar 2", sortOrder: "2.3" }
    ]), 300);
    
    getMainData(mains);
    getSubData(subs);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <ul data-bind="foreach: mains">
      <li>
        <p data-bind="text: title + ' ' + sortOrder">
        <ul data-bind="foreach: subs">
          <li data-bind="text: description + ' ' + sortOrder"></li>
        </ul>
      </li>
    </ul>

    【讨论】:

    • 非常有帮助,感谢您的出色回答。这很有指导意义。
    猜你喜欢
    • 2012-09-08
    • 2015-10-05
    • 1970-01-01
    • 2023-04-06
    • 2015-06-22
    • 2013-05-01
    • 2015-03-20
    • 1970-01-01
    相关资源
    最近更新 更多