KnockoutJS 按子 属性 数组对 ObservableArray 条目进行分组
KnockoutJS Grouping ObservableArray entries by child Property array
一段时间以来,我一直在思考实现这一结果的最佳方式,并成功调整了我的显示模板和 JS,但它不可扩展。
我有一个 observableArray,ContentGrid[],数组中的每个项目都有多个对象,包括一个包含对象 Product & Docs 的对象 Taxonomies{}。 Product 和 Docs 都包含与其分类相匹配的项目数组,例如 Product 包含 [ProductA] 和 Docs:[Photos].
我希望能够按产品 A、产品 B、产品 C 等对结果进行分组,但是,我似乎无法找到使之成为可能的正确语法。
您可以使用遍历 ContentGrid
数组的 pureComputed
为每个唯一产品创建一个组。
下例显示:
- 创建一个
Map
来保存组。它的 keys 指的是 product 并且它的 values 将是您网格的一部分(即部分 ContentGrid
s)
- 使用
for ... of
遍历网格的行
- 使用
for ... of
遍历行中的所有产品
- 确保
Map
中有一个空数组(= 内容网格)
- 确保此行已记录在此产品的组中
为了更容易将组渲染到 UI,我将 Map
实例转换为视图模型数组。每组得到一个模型
title
指产品
rows
指的是网格中与该产品匹配的部分。
如您所见,此分组将复制具有多个产品的行。如果您想实施不同的分组策略,您可能需要更新内部循环。
const contentGrid = ko.observableArray([
{ id: "Grid row 1", taxonomies: { product: [{ id: "Product C" }] } },
{ id: "Grid row 2", taxonomies: { product: [{ id: "Product B" }] } },
{ id: "Grid row 3", taxonomies: { product: [{ id: "Product A" }] } },
{ id: "Grid row 4", taxonomies: { product: [{ id: "Product A" }, { id: "Product B" }] } },
{ id: "Grid row 5", taxonomies: { product: [{ id: "Product A" }, { id: "Product B" }, { id: "Product C" }] } }
]);
// A computed list of all rows
const rowsByProduct = ko.pureComputed(() => {
const rowsByProductId = new Map();
for (const contentRow of contentGrid()) {
for (const product of contentRow.taxonomies.product) {
if (!rowsByProductId.has(product.id)) {
rowsByProductId.set(product.id, []);
}
// Add the content row for this product
rowsByProductId.get(product.id).push(contentRow);
}
}
// Format our map's entries to viewmodels
return Array
.from(rowsByProductId.keys())
.sort()
.map(productId => ({
title: productId,
rows: rowsByProductId.get(productId)
}));
});
ko.applyBindings({ contentGrid, rowsByProduct })
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h2>By product</h2>
<ul data-bind="foreach: rowsByProduct">
<li>
<p data-bind="text: title"></p>
<ul data-bind="foreach: rows">
<li data-bind="text: id"></li>
</ul>
</li>
</ul>
一段时间以来,我一直在思考实现这一结果的最佳方式,并成功调整了我的显示模板和 JS,但它不可扩展。
我有一个 observableArray,ContentGrid[],数组中的每个项目都有多个对象,包括一个包含对象 Product & Docs 的对象 Taxonomies{}。 Product 和 Docs 都包含与其分类相匹配的项目数组,例如 Product 包含 [ProductA] 和 Docs:[Photos].
我希望能够按产品 A、产品 B、产品 C 等对结果进行分组,但是,我似乎无法找到使之成为可能的正确语法。
您可以使用遍历 ContentGrid
数组的 pureComputed
为每个唯一产品创建一个组。
下例显示:
- 创建一个
Map
来保存组。它的 keys 指的是 product 并且它的 values 将是您网格的一部分(即部分ContentGrid
s) - 使用
for ... of
遍历网格的行
- 使用
for ... of
遍历行中的所有产品
- 确保
Map
中有一个空数组(= 内容网格)
- 确保此行已记录在此产品的组中
为了更容易将组渲染到 UI,我将 Map
实例转换为视图模型数组。每组得到一个模型
title
指产品rows
指的是网格中与该产品匹配的部分。
如您所见,此分组将复制具有多个产品的行。如果您想实施不同的分组策略,您可能需要更新内部循环。
const contentGrid = ko.observableArray([
{ id: "Grid row 1", taxonomies: { product: [{ id: "Product C" }] } },
{ id: "Grid row 2", taxonomies: { product: [{ id: "Product B" }] } },
{ id: "Grid row 3", taxonomies: { product: [{ id: "Product A" }] } },
{ id: "Grid row 4", taxonomies: { product: [{ id: "Product A" }, { id: "Product B" }] } },
{ id: "Grid row 5", taxonomies: { product: [{ id: "Product A" }, { id: "Product B" }, { id: "Product C" }] } }
]);
// A computed list of all rows
const rowsByProduct = ko.pureComputed(() => {
const rowsByProductId = new Map();
for (const contentRow of contentGrid()) {
for (const product of contentRow.taxonomies.product) {
if (!rowsByProductId.has(product.id)) {
rowsByProductId.set(product.id, []);
}
// Add the content row for this product
rowsByProductId.get(product.id).push(contentRow);
}
}
// Format our map's entries to viewmodels
return Array
.from(rowsByProductId.keys())
.sort()
.map(productId => ({
title: productId,
rows: rowsByProductId.get(productId)
}));
});
ko.applyBindings({ contentGrid, rowsByProduct })
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h2>By product</h2>
<ul data-bind="foreach: rowsByProduct">
<li>
<p data-bind="text: title"></p>
<ul data-bind="foreach: rows">
<li data-bind="text: id"></li>
</ul>
</li>
</ul>