angulardrag-and-dropcss-animationsangular-cdk

Different cdk-drag-preview animation based on drop container


I'm trying to get a different animation when releasing a dragged component, based on the drop container.

Basically, I have two cdkDropList. One is a list of cards (multiple draggable elements), the other is a card viewer with only one element, twice the size. The user can drag a card from the list to the viewer, to have a better view.

When the user drag a card, then release it, two cases are possible:

You can animate the card sliding to its destination position with the following css:

.cdk-drag-animating {
  transition: transform 300ms cubic-bezier(0, 0, 0.2, 1);
}

So far, so good.

However, I must now add a conditional css rule, adding a "transform: scale(2);" if the drop container is the viewer.

And this is where I'm stuck!

I'm trying to avoid direct DOM access, following the angular guideline, so I want to add a class to the card while its animated. But CDK don't seem to have a way to get a reference of the preview/animating component!

I've managed to get the target size and the dragging component, with the following code in my component ts:

  onDragEnter(event: CdkDragEnter) {
    if (_.contains(event.container.element.nativeElement.classList,"large")){
      this.targetSize= "large";
    } else {
      this.targetSize= "medium";
    }
  }      
  onDragRelease(event: CdkDragRelease) {
    this.renderer.addClass(event.source.element.nativeElement, this.targetSize);
  }

However, this reference is of the dragging object, and NOT the preview one! When putting a very long timer on the animation to allow me to inspect it, I can see the following DOM elements:

    <div _ngcontent-auk-c7="" cdkdrag="" class="cdk-drag large" 
ng-reflect-data="[object Object]" style="display: none;">...</div>
    
    <div _ngcontent-auk-c7="" cdkdrag="" class="cdk-drag cdk-drag-preview cdk-drag-animating" 
ng-reflect-data="[object Object]" style="touch-action: none; -webkit-user-drag: none; -webkit-tap-highlight-color: transparent; user-select: none; width: 135px; height: 175px; transform: translate3d(415px, 84px, 0px); pointer-events: none; margin: 0px; position: fixed; top: 0px; left: 0px; z-index: 1000;" dir="ltr"><!----><div _ngcontent-auk-c7="" class="card-holder medium"><app-card-base _ngcontent-auk-c7="" _nghost-auk-c8="" ng-reflect-card="[object Object]" ng-reflect-size="medium"><div _ngcontent-auk-c8="" class="card-container medium flip-front" ng-reflect-klass="card-container" ng-reflect-ng-class="medium,flip-front">...</div>

As you can see, we have two elements, one with the correct class "large", but on "display:none", and a second, with the classes "cdk-drag-preview cdk-drag-animating", but not the new class "large".

So, as I cannot add a class to this second element, I cannot make it conditionally change its animation...

A strange side effect is that the new class "large" is added to the card, and future cdk-drag-preview from this card will then have the "large" class! However, it's not good since it seems to indicate I should had my class before the drag start, when I don't know if the user will really drag it to the viewer dropList..

TL;DR :


Solution

  • Ok so it's not really what I wanted, but it works..

    In the cdkDragReleased event, I get a reference of the cdkDragPreview element with "document.querySelector"...

    I don't think it follow the guidelines of Angular, but at least I made it work, and now my card animation scales correctly based on the target DropList..

      onDragRelease(event: CdkDragRelease) {
        const preview = new ElementRef<HTMLElement>(document.querySelector(".cdk-drag.cdk-drag-preview"));
        this.renderer.addClass(preview.nativeElement, this.targetSize);
      }