In angular 18 I have implemented a simple component using Angular drag & drop cdk (u can see better examples here):
import {Component} from '@angular/core';
import {
CdkDrag,
CdkDragDrop,
CdkDragPlaceholder,
CdkDropList,
moveItemInArray,
} from '@angular/cdk/drag-drop';
@Component({
standalone: true,
selector: 'cdk-drag-drop-custom-placeholder-example',
template: `<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
@for (movie of movies; track movie) {
<button (click)="moveUp(movie)">Up</button>
<button (click)="moveDown(movie)">Down</button>
<div class="example-box" cdkDrag>
<div class="example-custom-placeholder" *cdkDragPlaceholder></div>
{{movie}}
</div>
}
</div>`,
styleUrl: 'cdk-drag-drop-custom-placeholder-example.css',
imports: [CdkDropList, CdkDrag, CdkDragPlaceholder],
})
export class CdkDragDropCustomPlaceholderExampleComponent {
movies = [
'Episode I - The Phantom Menace',
'Episode II - Attack of the Clones',
'Episode III - Revenge of the Sith',
'Episode IV - A New Hope',
'Episode V - The Empire Strikes Back',
];
moveUp(item: string) {
const index = this.movies.indexOf(item);
moveItemInArray(this.movies, index, index - 1);
}
moveDown(item: string) {
const index = this.movies.indexOf(item);
moveItemInArray(this.movies, index, index + 1);
}
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
}
}
this simple code works and when dragging the movies around then there is animation which is moving them in the array,
The problem starts when using the buttons up/down to move the items, they are switching places but instantly and with no animation at all.
I would love to know how to enable the animation when changing the array manually. Thanks!
Ok, I have created a workaround solution with up and down (not for any other list organize).
I have been notice that when i drag and move the element around then i see that the translate3d style is been added to the place holder element and to the element its been changed places with.
my solution:
moveUp(item: item) {
this.animateMove(item, 'up');
}
moveDown(item: item) {
this.animateMove(item, 'down');
}
animateMove(item: item, direction: 'up' | 'down') {
const index = this.itemList().indexOf(item);
const element = document.getElementById(item.questionId.toString());
if (element) {
this.renderer.setStyle(element, 'transition', 'transform 0.3s ease');
this.renderer.setStyle(
element,
'transform',
`translate3d(0px, ${direction === 'up' ? '-60px' : '60px'}, 0px)`,
);
const changeWithElement =
direction === 'up'
? (element.previousElementSibling as HTMLElement)
: (element.nextElementSibling as HTMLElement);
console.log('current', element);
console.log('previes', changeWithElement);
this.renderer.setStyle(
changeWithElement,
'transition',
'transform 0.3s ease',
);
this.renderer.setStyle(
changeWithElement,
'transform',
`translate3d(0px, ${direction === 'up' ? '60px' : '-60px'}, 0px)`,
);
setTimeout(() => {
this.renderer.removeStyle(element, 'transition');
this.renderer.removeStyle(element, 'transform');
this.renderer.removeStyle(changeWithElement, 'transition');
this.renderer.removeStyle(changeWithElement, 'transform');
moveItemInArray(
this.rulesList(),
index,
direction === 'up' ? index - 1 : index + 1,
);
this.updateGlobalRatings();
}, 300);
}
}
i also added id to each div item like this:
<div
class="list-item"
[class.opacity-40]="isDragging"
(cdkDragStarted)="onDragStarted()"
(cdkDragReleased)="onDragReleased()"
cdkDrag
[id]="item.questionId"
>
the concept behind this is to track the element i want to move, then by the button i will take its previews element or its next and then add to both of them the correct style with the transition so the animation will work (just adding the style didn't do the job)
this is workaround but it did great for my case, doing something like shuffle will or replacing different elements locations that are not one next to each other will require taking the wanted elements ids and all the ones that are between and change each one transition separately. if someone have better solution maybe one that use the drag & drop functions and properties plz share it here (: