我的视图模型中有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.
答案 0 :(得分:1)
让我们首先以更易读的格式探索您提供的数据:
{
ID: 4,
mainDescription: "foo foo foo",
SortOrder: "1"
}
{
ID: 21,
SubDescription: "bar bar bar",
SortOrder: "1.1"
}
从您想要的输出中,我们了解到我们需要:
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]
}
通过建议的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>
因为我们有数字sortKey
道具,我们可以进行数字比较来排序:
// Sort utils
const numericSort = (x, y) => x > y ? 1 : x < y ? -1 : 0;
const vmSort = (vm1, vm2) => numericSort(vm1.sortKey, vm2.sortKey);
我们可以按照groupKey
:
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);
&#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;