I am using ngForOf to list dates, each date is represented by id
property which is actually its index + 1. All the dates are present in form of object in an array. Also, each date is a component instance.
The thing with ngForOf is that whenever I delete a date from the list, the whole DOM refreshes and the ID's are assigned all over again.
<app-date *ngFor="let date of dates | callback: filterDates; index as i" (delete)="del(i)"></app-date>
The Problem
Now when I say "delete", I am not splicing/removing the date from the array, but setting the action
property of the date to "deleted"
. This is so that I don't have to make HTTP requests for every date to delete it from the database.
Once the action
is "deleted"
, the date does not show up in the DOM, but is still present in the array. So the next time DOM refreshes, it is going to reassign the IDs and now I am going to have duplicate ID's in the array. This has many consequences, the biggest one being that I cannot delete the dates with the same ID.
I also tried to change ID of the date on every delete event but that also messes up the array.
Important
I am aware of trackBy
, but I don't understand how I can apply it to solve this problem and don't see a problem on the internet that relates to this.
Thanks.
I was able to solve the problem.
There are basically two arrays, one is the dates
array through which I am traversing to render dates, the other array is the one that contains the DOM elements that represent each date that is showed on the screen. Angular does not care about what id
or index the the date has in the dates
array present in the component.ts file. By default, it tracks each element in the ngFor
loop through index in the DOM array. This array keeps changing for every add/remove operation that occurs.
The mistake I made was that I used the DOM array index as the id
of the date. Now due to the removal of any date, the DOM array was refreshing, and since I was never actually deleting or splicing the date from the array, there were always some duplicate id
's in the array.
There should be a separate ID generation function, or maybe simply a number type property that keeps incrementing on every pushDate()
operation. This will, to some extent, solve the problem of id
duplication. Although, Angular still does not care about the id
and it can only identify each date element by its index in the DOM array, so, in order to delete a specific date you need its index in the DOM array.
<app-date *ngFor="let date of dates | callback: filterDates; index as i" [id]="dateID" (delete)="del(i, $event)"></app-date>
Now, (delete)
will return a string that shows the date, for example: 2020-8-15. This date, along with action
property of that specific date will identify the date to be set to deleted
. Here is how I do it:
getArrayIndex = (index: number, date: string): number => {
for (let i = 0; i < this.dates.length; i++) {
if(i == index && date == this.dates[i]['date']) {
if(this.dates[i]['action'] == 'deleted') {
return this.getArrayIndex(i + 1, date);
}
else {
return i;
}
}
else if(i == index && date != this.dates[i]['date']) {
return this.getArrayIndex(i + 1, date);
}
else if(i != index) {
continue;
}
else {
return i;
}
}
}
del = (num: number, event: string) => {
let i = this.getArrayIndex(num, event);
this.dates[i]['action'] = 'deleted';
}
The del
function first finds the correct index of the date that is to be deleted in the dates
array through getArrayIndex()
. Once the date
is found the action
property of that particular date object is set to "deleted"
.