1. Initialize draggable element
We initialize this template in a DragDropComponent:
<div #draggable class="draggable"></div>
.draggable {
width: 200px;
height: 200px;
background-color: #ccc
}
2. Initialize events
We init observables from events that we will need later:
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. Create drag and drop logic
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. Subscribe and make moves visible
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)`;
});
}
And here you go! 🥳
Note : some angular libraries for drag & drop use this technique to handle events, for example angular-draggable-droppable.