I have 2 observable arrays in my view model:
self.main = ko.observablearray();
self.sub = ko.observablearry();
Main is loaded with a getjson call and returns 12 items with a description / sort order (ie 1-12) into the self.main array and the sub returns child descriptions to the main.
The json for main return:
<storedProc_Result>
<ID>4</ID>
<mainDescription>
foo foo foo
</mainDescription>
<SortOrder>1</SortOrder>
</storedProc_Result>
The json for sub return:
<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>
How will I loop through and combine these 2 arrays based off of the SortOrder value so I can do a foreach loop on my View page? IE
Let's first explore the data you've provided in a more readable format:
{
ID: 4,
mainDescription: "foo foo foo",
SortOrder: "1"
}
{
ID: 21,
SubDescription: "bar bar bar",
SortOrder: "1.1"
}
From your desired output, we learn that we need:
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]
}
With the structure of viewmodels as proposed, we can create the view:
<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>
Because we have numeric sortKey
props, we can do a numeric compare to sort:
// Sort utils
const numericSort = (x, y) => x > y ? 1 : x < y ? -1 : 0;
const vmSort = (vm1, vm2) => numericSort(vm1.sortKey, vm2.sortKey);
We can group a list of SubViewModel instances by their groupKey
:
const groupSubs = subs => subs.reduce(
(gs, s) => Object.assign(
gs,
{ [s.groupKey]: (gs[s.groupkey] || []).concat(s) }
), { }
)
Now, we can create a nice chain from data to app using ko.pureComputed
instances.
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));
This flow illustrated in a working example:
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>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.