1. Initialisation de l'élément "draggable"


On initialise ce template dans un composant DragDropComponent:


  <div #draggable class="draggable"></div>
  .draggable {
      width: 200px;
      height: 200px;
      background-color: #ccc
  }


2. Initialisation des évènements


On initialise des observables basés sur les évènements dont on aura besoin plus tard.


import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { Observable, fromEvent } from 'rxjs';

@Component({
  selector: 'app-drag-drop',
  templateUrl: './drag-drop.component.html',
  styleUrls: ['./drag-drop.component.scss']
})
export class DragDropComponent implements OnInit {

  @ViewChild('draggable', { static: true }) draggable: ElementRef; // get html element

  private start$: Observable<MouseEvent>;
  private move$: Observable<MouseEvent>;
  private stop$: Observable<MouseEvent>;

  constructor() {}

  ngOnInit(): void {
    this.start$ = fromEvent(this.draggable.nativeElement, 'mousedown');
    this.move$ = fromEvent(document, 'mousemove') as Observable<MouseEvent>;
    this.stop$ = fromEvent(document, 'mouseup') as Observable<MouseEvent>;
  }
}


3. Création de la logique de drag & drop


  import { fromEvent, Observable, switchMap, takeUntil } from 'rxjs';
  (...)

  private drag$: Observable<MouseEvent>;

  ngOnInit(): void {
    (...)

    this.drag$ = this.start$.pipe( // init with the mousedown on draggable element
      switchMap(() => this.move$.pipe( // redirect to mousemove
        takeUntil(this.stop$) // stop when mouseup
      ))
    );
  }


4. Souscrire et rendre les mouvements visibles


  ngOnInit(): void {
    (...)

    this.drag$.subscribe(event => {
      const { layerX: x, layerY: y } = event as any; // type any in order to use non-standard layerX and layerY propertiesthis.draggable.nativeElement.style.transform = `translateX(${x}px) translateY(${y}px)`;
    });
  }


Et voilà ! 🥳


Note : quelques librairies Angular utilisent cette technique pour gérer le drag & drop, par exemple angular-draggable-droppable.