J'ai plusieurs éléments CdkDrag qui sont rendus à partir d'une boucle ngFor sur un tableau de mon composant. lorsque je supprime un élément, je raccorde le tableau. Ensuite, certains des éléments mettront à jour leur position. comment éviter cela?
J'ai essayé d'obtenir la freeDragPosition de tous les éléments glissables avant de supprimer l'un d'eux, puis de réinitialiser leur position, mais cela n'a pas fonctionné.
c'est mon app.component.html
<div class="container" id="container">
<div *ngFor="let f of fields; let i = index;"
class="textField"
[attr.data-guid]="f.guid"
(mouseenter)="onFieldHover($event)"
cdkDrag
cdkDragBoundary="#container"
(cdkDragEnded)="onDragEnded($event)"
[cdkDragFreeDragPosition]="f.position">
<div class="textField-inner">
<span style="color: hotpink; font-weight: bold">{{f.guid}}</span>
</div>
<div class="textField-options">
<div class="textField-move" cdkDragHandle>
<svg width="24px" fill="currentColor" viewBox="0 0 24 24">
<path d="M10 9h4V6h3l-5-5-5 5h3v3zm-1 1H6V7l-5 5 5 5v-3h3v-4zm14 2l-5-5v3h-3v4h3v3l5-5zm-9 3h-4v3H7l5 5 5-5h-3v-3z"></path>
<path d="M0 0h24v24H0z" fill="none"></path>
</svg>
</div>
<div class="textField-remove">
<i class="fas fa-trash-alt" (click)="onRemoveTextField(i)"></i>
</div>
</div>
</div>
</div>
<button type="button" (click)="onTextFieldAdded()">Add a field</button>
et voici mon app.component.ts
import { Component } from '@angular/core';
import {CdkDrag, CdkDragEnd} from '@angular/cdk/drag-drop';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.scss' ]
})
export class AppComponent {
name = 'Angular';
fields: Field[] = [];
draggables: CdkDrag<any>[] = [];
onDragEnded(event: CdkDragEnd){
if(!this.draggables.find(f => f == event.source)){
this.draggables.Push(event.source);
}
}
onFieldHover(event: any){
if(event.target.classList.contains('initialPosition')){
event.target.classList.remove('initialPosition');
event.target.style.transform = "translate3d(250px, 180px, 0px)";
}
}
onTextFieldAdded() {
let field = new Field();
field.index = this.fields.length;
field.guid = this.newGuid();
this.fields.Push(field);
}
onRemoveTextField(index: number){
let positions : any[] =[];
this.draggables.forEach(drag => {
let pos = { guid: drag.element.nativeElement.getAttribute("data-guid"), pos: drag.getFreeDragPosition() };
positions.Push(pos);
console.log(pos);
});
this.fields.splice(index, 1);
positions.forEach(p => {
let newPos = {x: p.pos.x, y: p.pos.y};
console.log(newPos);
this.fields.find(f => f.guid == p.guid).position = newPos;
});
}
newGuid(): string{
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
}
export class Field{
index: number;
guid: string;
position: {x: number, y: number}
}
Je souhaite que mon élément reste dans sa position actuelle lorsque l'un des éléments a été supprimé.
voici un .gif représentant le problème
voici un stackblitz https://stackblitz.com/edit/angular-p3yfe7
Le problème est que vous n'avez pas spécifié de fonction trackBy
dans votre *ngFor
, cela provoquera un nouveau rendu des objets chaque fois que le tableau change:
Vous devez créer votre *ngFor
comme ça:
*ngFor="let f of fields; let i = index; trackBy: trackByField"
Et mettez à jour votre composant pour avoir une méthode trackByField
trackByField = (i: number, field: Field) => field.guid;
Ensuite, les éléments qui ont déjà été déplacés restent dans leur position et les éléments non déplacés seront toujours réorganisés