There is an alternative approach that does not use mat-flex, but instead uses a div with position absolute and manual animation.
Consider the following HTML structure:
<div class="container">
<div class="column">
<mat-card class="custom">
{{order|json}}
</mat-card>
</div>
<div class="column">
<div #card (click)="sortOrder(0)">
<mat-card class="custom2">
custom 0
</mat-card>
</div>
<div #card (click)="sortOrder(1)">
<mat-card class="custom2">
custom 1
</mat-card>
</div>
<div #card (click)="sortOrder(2)">
<mat-card class="custom2">
custom 2
</mat-card>
</div>
</div>
</div>
Using the following CSS styles:
.container{
display:flex;
}
.column{
margin-left:15px;
}
.column>div
{
position:absolute;
}
The concept involves creating a manual animation. To achieve this, we use @ViewChildren
to select the "cards" and inject the AnimationBuilder in the constructor.
timing = '500ms ease-in-out';
initPos=0;
@ViewChildren('card', { read: ElementRef }) items: QueryList<ElementRef>;
private player: AnimationPlayer;
constructor(private builder: AnimationBuilder) {}
The "animate" function takes a nativeElement and a top position as parameters to create an animation for moving the element. An additional parameter "last" can be used to perform an action when the animation finishes.
animate(element: any, top: string | number,last:boolean) {
const myAnimation = this.builder.build([
animate(this.timing, style({ top: top}))
]);
this.player = myAnimation.create(element);
if (last)
{
this.player.onDone(()=>{
window.scrollTo(0, 0);
})
}
this.player.play();
}
The main task is to calculate the position "top" based on an array order that changes upon clicking.
sortOrder(index: number) {
const value = this.order[index];
if (value != 0) {
this.order = this.order.map(
(x, i) => (x = i == index ? 0 : x < value ? x + 1 : x)
);
}
let pos = this.initPos ||0;
for (let i=0;i<this.order.length;i++)
{
const index=this.order.findIndex(x=>x==i);
const card = this.items.find((_, j) => j == index);
if (card) {
this.animate(card.nativeElement, pos ? pos + 'px' : 0,i==this.order.length-1);
pos += card.nativeElement.getBoundingClientRect().height;
}
}
}
Lastly, remember to call the sortOrder function in ngAfterViewInit.
ngAfterViewInit()
{
this.initPos=this.items.first.nativeElement.getBoundingClientRect().top;
this.sortOrder(0)
}
Here is the link to the StackBlitz demo