【发布时间】:2021-09-18 18:38:47
【问题描述】:
我有一个小的示例 Angular 应用程序,我正在尝试使用 kendo UI 抽屉组件。我的问题与抽屉本身无关,但它具有一般性。
我有一个 items 对象数组,抽屉根据它填充:
export const items = [
{
text: 'France',
icon: 'user',
selected: false,
expanded: false,
parent: true,
level: 0,
id: '0',
children: [
{
text: 'Paris',
level: 1,
id: '0.1',
},
{
text: 'Lyon',
selected: false,
expanded: false,
parent: true,
level: 1,
id: '0.2',
children: [
{
text: 'Lyon 1',
level: 2,
id: '0.2.1',
},
{
text: 'Lyon 2',
level: 2,
id: '0.2.2',
},
],
},
],
},
{
text: 'Italy',
icon: 'gear',
expanded: false,
selected: false,
parent: true,
level: 0,
id: '1',
children: [
{
text: 'Rome',
level: 1,
id: '1.1',
},
{
text: 'Milan',
level: 1,
id: '1.2',
},
],
},
];
现在,在组件加载或用户第一次选择一个项目时,我使用这个函数克隆这个数组:
public resetItems(): Array<any> {
const arr = [];
items.forEach((item) => {
arr.push(Object.assign({}, item));
});
return arr;
}
然后我将返回的数组分配给一个临时数组,如下所示:
if (this.newItems.length === 0) {
this.newItems = this.resetItems();
}
用户可以选择、展开、折叠项目。通过单击一个项目,我相应地设置了 appr- 属性(选中、展开)。
在上面的示例数据中,我有一个父母法国和两个孩子(巴黎、里昂),其中里昂还有另外两个孩子(用于测试目的)。现在,如果我单击 France 并在 France 对象的 items 数组中展开抽屉,属性 selected 和 expanded 仍然为 false。这正如预期的那样,因为我对newItems 数组而不是items 本身进行了所有这些修改。
但是如果我扩展里昂,那么里昂上的属性selected 和expanded 在items 数组中设置为true,这不应该发生。为什么是这样?在我看来,newItems 和 items 数组似乎是连接在一起的。但他们不应该。
我也编写了两个小函数,以便在 newItems 上设置 selected 和 expanded 以将所有项目设置为 false,如果我将此属性设置为 false,如下所示:
this.clearSelection(this.newItems);
this.clearExpandedState(this.newItems);
那么只有在这种情况下,我才会有一个 items 数组,其中里昂没有被选中也没有展开。
下面是分析这个的所有组件代码。
export class AppComponent {
public drawerExpanded = false;
public item: any = {};
public drawerItems = this.resetItems();
private newItems: any[] = [];
@ViewChild('drawer') drawer: DrawerComponent;
public onSelect(e: DrawerSelectEvent): void {
this.item = e.item;
const text = e.item.text;
// if item is no parent, then no action
if (!this.item.parent) {
return;
}
// if the drawer is collapsed and we click on one of the icons, we expand it
if (!this.drawerExpanded) {
this.drawer.toggle();
}
// we take a fresh start and reset the items to their original state,
// but only if we click the first time on any item
// in other cases 'newItems' must be not overridden
if (this.newItems.length === 0) {
this.newItems = this.resetItems();
}
// we set the 'selected' property on the clicked item to true (only parents should have the 'selected' property)
// but before do it, we clear all selection
// it has the effect, that the parent items have the '.k-state-selected' class too (background color set to primary)
const index = this.newItems.findIndex((i) => i.text === text);
this.clearSelection(this.newItems);
this.newItems[index].selected = true;
// we expand the clicked item - if not expanded - and add the children into the 'newItems' array
// else we remove the unnecessary items based on the 'id' field and set 'expanded' to false
if (!this.item.expanded) {
this.newItems[index].expanded = true;
this.addChildren(this.newItems, index, this.newItems[index].children);
} else {
this.newItems = this.removeChildren(this.item.id, this.newItems);
this.newItems[index].expanded = false;
}
// refresh the items in the component
this.drawerItems = this.newItems;
console.log(items);
}
public addChildren(arr, index: number, children: Array<any>) {
arr.splice(index + 1, 0, ...children);
}
public removeChildren(id: string, arr): Array<any> {
return arr.filter((item) => !item.id.startsWith(`${id}.`));
}
public clearSelection(arr) {
arr.forEach((item) => {
if (item.selected) {
item.selected = false;
}
});
}
public clearExpandedState(arr) {
arr.forEach((item) => {
if (item.expanded) {
item.expanded = false;
}
});
}
public resetItems(): Array<any> {
const arr = [];
items.forEach((item) => {
arr.push(Object.assign({}, item));
});
return arr;
}
toggle() {
this.clearSelection(this.newItems);
this.clearExpandedState(this.newItems);
this.newItems = [];
this.drawerItems = this.resetItems();
this.drawer.toggle();
}
}
【问题讨论】:
标签: javascript arrays typescript