1
votes

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:

  • The card is over the viewer. The card must then be animated to slide into the viewer while scaling to its new size.
  • The card is not over the viewer. The card must then slide back to its original position in the list, while keeping its size.

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 conditionnaly 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 :

  • I need to dynamically add a class to cdk-drag-preview based on which dropList is targeted.
  • cdk-drag-preview don't seem to be able to be referenced in any of the cdk-drag events
  • I thus cannot add my class to it and change the final animation once the drag as started.
2

2 Answers

2
votes

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);
  }
1
votes

HTML

(cdkDropListEntered)="cdkDropListEntered($event)"
(cdkDropListExited)="cdkDropListExited($event)"

TypeScript

  cdkDropListEntered(event: CdkDragEnter<string[]>) {
    const preview = new ElementRef<HTMLElement>(document.querySelector('.cdk-drag.cdk-drag-preview'));
    this.renderer.addClass(preview.nativeElement, 'class-name');
  }

  cdkDropListExited(event: CdkDragExit<string[]>) {
    const preview = new ElementRef<HTMLElement>(document.querySelector('.cdk-drag.cdk-drag-preview'));
    this.renderer.removeClass(preview.nativeElement, 'class-name');
  }