将元素从Array1更改为Array2,反之亦然



看起来很简单,但我不知道如何有效地解决这个问题。

我有两个数组activeClassesdoneClasses,每个数组都包含JavaScript对象作为它们的元素。

每个元素都应该能够标记为"活动"或"完成",并且应该从当前数组中删除,如果单击"保存"后其状态发生变化,则应将其添加到另一个数组中。如何在不混淆数组索引的情况下实现这一点?除了选择多个元素时,行为与预期一致:

https://stackblitz.com/edit/angular-etzocz?file=src%2Fapp%2Fapp.component.html

TS

import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
activeChanged:Array<boolean> = [];
doneChanged:Array<boolean> = [];
toggleActive(i) {
this.activeChanged[i] = !this.activeChanged[i];
console.log('activeChanged:');
console.log(this.activeChanged);
}
toggleDone(i) {
this.doneChanged[i] = !this.doneChanged[i];
console.log('doneChanged:');
console.log(this.doneChanged);
}
save() {
var activeToBeDeleted:Array<number> = [];
var doneToBeDeleted:Array<number> = [];
//Check if active classes have changed
this.activeChanged.forEach(function (elem, index) {
//Has changed
if (elem) {
this.doneClasses.push(this.activeClasses[index]);
//Add to activeToBeDeleted
activeToBeDeleted.push(index)
}
}.bind(this))
//Check if done classes have changed
this.doneChanged.forEach(function (elem, index) {
//Has changed
if (elem) {
this.activeClasses.push(this.doneClasses[index]);
//Add to doneToBeDeleted
doneToBeDeleted.push(index)
}
}.bind(this))
console.log('before deletion')
console.log(this.activeClasses)
console.log(this.doneClasses)
//Delete array elements that were changed
activeToBeDeleted.forEach(function(elem) {
this.activeClasses.splice(elem,1)
}.bind(this))
doneToBeDeleted.forEach(function(elem) {
this.doneClasses.splice(elem,1);
}.bind(this))
console.log('after deletion')
console.log(this.activeClasses)
console.log(this.doneClasses)
//Rewrite activeChanged and doneChanged arrays again with false
this.activeChanged = new Array(this.activeClasses.length).fill(false)
this.doneChanged = new Array(this.doneClasses.length).fill(false)

}

//As from database
activeClasses:Array<Object> = [
{
name: 'test1'
},
{
name: 'test2'
}
];

doneClasses:Array<Object> = [
{
name: 'test3'
},
{
name: 'test4'
}
];
ngOnInit() {
//Fill activeChanged and doneChanged with false by default
this.activeChanged = new Array(this.activeClasses.length).fill(false)
this.doneChanged = new Array(this.doneClasses.length).fill(false)
}
}

HTML

<div *ngFor="let active_class of activeClasses; let i = index" style="background-color: blue; text-align: center; padding: 20px; color: white;">
<button *ngIf="!activeChanged[i]" (click)="toggleActive(i)">Mark as done</button>
<button *ngIf="activeChanged[i]" (click)="toggleActive(i)">Mark as active</button>
{{ active_class.name }}
</div>
<div *ngFor="let done_class of doneClasses; let i = index" style="background-color: red; text-align: center; padding: 20px; color: white;">
<button *ngIf="!doneChanged[i]" (click)="toggleDone(i)">Mark as active</button>
<button *ngIf="doneChanged[i]" (click)="toggleDone(i)">Mark as done</button>
{{ done_class.name }}
</div>
<button (click)="save()">Save</button>

这是因为当您按自然排序顺序拼接项目时,在删除第一个项目后,项目的数组索引会发生变化。

解决方案是在拼接之前调用reverse(),这样可以在不影响索引的情况下向下遍历数组。

这修复了它:

//Delete array elements that were changed
activeToBeDeleted.reverse().forEach(function(elem) {
this.activeClasses.splice(elem,1)
}.bind(this))
doneToBeDeleted.reverse().forEach(function(elem) {
this.doneClasses.splice(elem,1);
}.bind(this))

为什么它有效?

首先,activeChangeddoneChanged是在修改的项的索引处存储布尔值的数组(活动或完成,请参见toggle方法(。当您在Save方法中第一次在这些数组上循环时,它会按升序在项上循环,因此,您将按升序将索引存储到activeToBeDeleteddoneToBeDeleted数组中。

因此,在那之后,当您在activeToBeDeleteddoneToBeDeleted数组上循环并从activeClassesdoneClasses中删除时,虽然第一次删除有效,但其他删除都不起作用,因为第一次删除操作从数组的开头删除了一个项,并导致以下所有索引移位和不正确。

该解决方案之所以有效,是因为通过反转索引列表(按降序排列(,可以从数组的末尾开始删除,从而自然地保留所有索引。我建议你用钢笔和铅笔,实际上这是一种经典的图案。

最新更新