组合/构建多个敲除可观察阵列

时间:2018-02-22 15:51:25

标签: javascript jquery arrays sorting knockout.js

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

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

Main加载了一个getjson调用,并将带有描述/排序顺序(即1-12)的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值循环并组合这两个数组,以便在View页面上进行foreach循环? I.E.

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

1 个答案:

答案 0 :(得分:1)

1。数据

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

主要

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

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

2。视图模型

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

AppViewModel

{
  mains: [ /* MainViewModel */ ]
}

A MainViewModel

{ 
  title: "foo foo foo",
  numberLabel: "1",
  subs: [ /* SubViewModel */ ],

  // The label as a number
  sortOrder: parseInt("1", 10)
}

A 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。观点

通过建议的viewmodels结构,我们可以创建视图:

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

工作示例

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

&#13;
&#13;
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);
&#13;
<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>
&#13;
&#13;
&#13;