我正在建立一个多选检查组项目列表。目标是一次仅拥有一个活动组。因此,用户可以选择父项-但是如果他们选择了子项,则该子组将成为焦点,而选中的父项将变为未选中状态。
<div class="checkboxhandler">
<input
type="checkbox"
checked={{@item.checked}}
onclick={{action @onClick @item.id}}
>
<label>{{@item.label}} -- checked: {{@item.checked}}</label>
{{#if @item.children}}
{{#each @item.children as |child|}}
<CheckboxGroup @item={{child}} @onClick={{@onClick}} />
{{/each}}
{{/if}}
</div>
我已经了解了带有递归帮助程序检查的复选框。
这是辅助树-取消选择的逻辑发生在这里。此应用程序还需要保留selectedItems的数组-但需要清除这些数组以及复选框。
const toggle = value => !value;
const disable = () => false;
// the roots / siblings are contained by arrays
export function check(tree, id, transform = toggle) {
if (tree === undefined) return undefined;
if (Array.isArray(tree)) {
return tree.map(t => check(t, id, transform));
}
if (tree.id === id || id === 'all') {
return checkNode(tree, id, transform);
}
if (tree.children) {
return checkChildren(tree, id, transform);
}
return tree;
}
function selectOnlySubtree(tree, id, transform) {
return tree.map(subTree => {
const newTree = check(subTree, id, transform);
if (!newTree.children || (transform !== disable && didChange(newTree, subTree))) {
return newTree;
}
return disableTree(subTree);
});
}
function isTargetAtThisLevel(tree, id) {
return tree.map(t => t.id).includes(id);
}
function checkNode(tree, id, transform) {
return {
...tree,
checked: transform(tree.checked),
children: disableTree(tree.children)
};
}
function disableTree(tree) {
return check(tree, 'all', disable);
}
function checkChildren(tree, id, transform) {
const newChildren = check(tree.children, id, transform);
const changed = didChange(tree.children, newChildren);
const checked = changed ? false : (
id === 'all' ? transform(tree.checked) : tree.checked
);
return {
...tree,
checked: checked,
children: check(tree.children, id, transform)
};
}
export function didChange(treeA, treeB) {
const rootsChanged = treeA.checked !== treeB.checked;
if (rootsChanged) return true;
if (Array.isArray(treeA) && Array.isArray(treeB)) {
return didChangeList(treeA, treeB);
}
if (treeA.children && treeB.children) {
return didChangeList(treeA.children, treeB.children);
}
return false;
}
function didChangeList(a, b) {
const compares = a.map((childA, index) => {
return didChange(childA, b[index]);
});
const nothingChanged = compares.every(v => v === false);
return !nothingChanged;
}
但是当前的错误正在发生
答案 0 :(得分:1)
您可以在每次进行false -> true
转换后,取消选中整棵树,除了包含当前正在更新的项目的图层。 。
例如:
.find
检查被设置为true的项目是否在图层中
checked
属性设置为true
checked: false
children
数组的项目进行递归
const turnOn = (options, id) => {
const target = options.find(o => o.id === id);
if (target) {
target.checked = true;
} else {
options.forEach(o => { o.checked = false; })
}
// Recurse
options.forEach(({ children = [] }) => turnOn(children, id));
}
var opts = options();
turnOn(opts, 3);
turnOn(opts, 4);
console.log("Checked after 3 & 4:", getChecked(opts));
turnOn(opts, 2);
console.log("Checked after 2:", getChecked(opts));
turnOn(opts, 6);
console.log("Checked after 6:", getChecked(opts));
function options() {
return [{
id: 1,
label: 'burger',
checked: false,
children: [{
id: 3,
label: 'tomato',
checked: false
}, {
id: 4,
label: 'lettus',
checked: false
}, {
id: 5,
label: 'pickle',
checked: false
}]
}, {
id: 2,
label: 'kebab',
checked: false,
children: [{
id: 6,
label: 'ketchup',
checked: false
}, {
id: 7,
label: 'chilli',
checked: false
}]
}];
};
function getChecked(opts) {
return opts.reduce((acc, o) => acc.concat(
o.checked ? o.label : [],
getChecked(o.children || [])
), []);
}
注意:我使用了一个递归函数,该函数只对树进行变异而不是返回新树,因为它更易于阅读
答案 1 :(得分:0)
我认为,如果在该项目本身上选择了某个项目,则停止存储信息,您实际上可以从很多中受益。这还将使您免于修改项目的麻烦。只需将所选ID的数组分别存储到数据即可。接下来,您只需要一个助手contains
/includes
。
因此您可以执行以下操作:
<input type="checkbox" checked={{contains item.id selectedIds}} />
接下来,您的规则集非常简单。有效选择仅包含相同 group 的项目。一组可能是
现在,不取消选择某些项目要容易得多,而是假设必须选择一项 (您单击的一项)以验证哪些已选择的项目仍然是有效的选择。那就很简单:所有这些都在同一组中。
因此,首先我们找到用户单击的项目的id
的组。如果父母名单包含id
,则我们使用父母名单,否则我们找到children
包含ID的父母:
const group = data.find(x => x.id === id)
? data
: data.find(p => p.children.find(c => c.id === id)).children;
现在我们有了这个小组。要获取组中的所有id
,我们需要const validIds = group.map(x => x.id)
。
接下来,新的selectedIds
应该是:
id
,selectedIds
中的所有旧validIds
。我们可以这样做:
const newSelectedIds = [
id,
...oldSelectedIds.filter(s => validIds.includes(s)),
];
here is a twiddle implementing this approach。
如果将ember-data
用于数据,则实际上可以进一步简化此操作。如果您有父母与子女之间的关系,则可以通过两种方式关注这种关系。因此,您可以通过item.parent.children
之类的方式查找所有兄弟姐妹。然后,您可以将模型而不是仅将id
传递给函数,并使用以下内容找到有效的组:
const group = item instanceof ParentModel
? this.data
: item.parent.children;
更具可读性。