angular9angular-animationsangulardraganddroplists

Angular 9 DragDrop - How to stop the DropList "Element-Shuffle" Animation


I am trying to disable the "auto sorting/shifting" animation of the Drop List. What I mean is, given a vertical list of draggables, when I drag the top element downward, the other elements visibly shift upward. This is cool for re-sorting, but I am doing a swap. Additionally, my draggable elements are lined up with other elements on the screen, so for the duration of the drag, when the drop list is moving its elements around, everything looks skewed.

For context, this is for a D&D Character creator, where the 6 stats (Str, Dex, Con, Int, Wis, and Cha) are in a vertical, non-draggable row. The drag-drop list of numeric values are along side it. When I drag the Str score down to swap with the Int score, then for the duration of the drag, the Dex score shifts up to Str, Con shifts up to Dex, etc. Everything works itself out on drop, but I don't want this behavior.

Ideally, the dragged element will leave a "shadow" of itself in the list, to prevent the other elements shifting around, but I'd be just as happy with like a blank space, or a gray space, or anything like that.

I have seen this behavior, but only on accident. I think it has to do with dragging components (instead of divs), but that seems more like a bug than a feature.

Is there a way to keep the drop list elements from shifting during a drag?

<div class="row" [formGroup]="statsFormGroup">
    <!-- non-movable stat names -->
    <div class="col col-6">
        <ul>
            <li *ngFor="let stat of stats" class="form-control mt-1">{{ stat | stat }}</li>
        </ul>
    </div>
    <!-- draggable scores -->
    <div class="col col-6" formArrayName="stats" cdkDropList (cdkDropListDropped)="scoreDrop($event)">
        <div *ngFor="let control of statsFormArray.controls; let i = index;" cdkDrag>
            <input type="text" [formControlName]="i" class="form-control mt-1" />
        </div>
    </div>
</div>

Solution

  • I hope you have found the solution for this, I am posting this answer for all the other people who are facing a similar issue.

    Step 1: Stop the animation of elements getting shifted and set the placeholder opacity to 0.5 to show a shadow of the picked up list item. We can do this by applying transform style.

       .cdk-drag:not(.cdk-drag-preview) {
          transform: none !important;
        }
    
        .cdk-drag-placeholder {
          opacity: 0.5;
        }

    Step 2: Highlight the row when the drag placeholder is on that row. We can achieve this by using the cdkDropListSorted event, which returns us the currentIndex and previousIndex of the list when we are dragging the element. After getting the indexes, we can easily change the styles by using the Angular Renderer2 Api.

    Here is a working example in stackBlitz: SwapElementsAngularMaterial