我正在使用单击和放下功能---在页面上以递归方式使用该模块,因此该模块具有父级和子级。
我遇到了一个问题,如果用户开始选择子级-然后选择父级-我想取消选择子级。尽管我不确定如何存储或监视为进行全局取消选择而选择的父项/子项的更改。
因此,用户已选择bacon3的子级。如果他们选择了父级,则需要取消选择子级,但我觉得我目前已锁定在模块范围内
答案 0 :(得分:4)
我认为这个示例将帮助您https://canary.ember-twiddle.com/468a737efbbf447966dd83ac734f62ad?openFiles=utils.tree-helpers.js%2C
所以,这是一个有趣的问题。事实证明,这与递归,javascript或复选框行为无关,而更多是递归问题。
这就是我所拥有的(使用更新的语法等(如果您可以选择升级到3.4,则绝对应该-只是梦想))
// wrapping-component.js
import Component from '@ember/component';
import { action, computed } from '@ember-decorators/object';
import { check } from 'twiddle/utils/tree-helpers';
export default class extends Component {
options = [{
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
}]
}];
@action
toggleChecked(id) {
const newTree = check(this.options, id);
this.set('options', newTree);
}
}
模板:
{{yield this.options (action this.toggleChecked)}}
及其用法:
// application.hbs
<WrappingComponent as |options toggle|>
{{#each options as |item|}}
<CheckboxGroup @item={{item}} @onClick={{toggle}} />
{{/each}}
</WrappingComponent>
CheckboxGroup是仅模板的组件:
// checkbox-group.hbs
<div class="checkboxhandler">
<input
type="checkbox"
checked={{@item.checked}}
onclick={{action @onClick @item.id}}
>
<label>{{@item.label}}</label>
{{#if @item.children}}
{{#each @item.children as |child|}}
<CheckboxGroup @item={{child}} @onClick={{@onClick}} />
{{/each}}
{{/if}}
</div>
和递归助手(这很糟,但是我只是在制作原型):
// utils/tree-helpers.js
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 selectOnlySubtree(tree, 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) {
return {
...tree,
checked: id === 'all' ? transform(tree.checked) : tree.checked,
children: check(tree.children, id, transform)
};
}
export function didChange(treeA, treeB) {
const rootsChanged = treeA.checked !== treeB.checked;
if (rootsChanged) return true;
if (treeA.children && treeB.children) {
const compares = treeA.children.map((childA, index) => {
return didChange(childA, treeB.children[index]);
});
const nothingChanged = compares.every(v => v === false);
return !nothingChanged;
}
return false;
}
希望这会有所帮助。