Last active
May 7, 2024 07:59
-
-
Save markleusink/7af171d5f17e7dc9714e69965fdabab9 to your computer and use it in GitHub Desktop.
Angular directive to make ngx-bootstrap modals draggable
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Directive, ElementRef, HostListener, AfterViewInit } from '@angular/core'; | |
/* | |
* Directive to add 'drag' support to Ngx Bootstrap modals (https://github.com/valor-software/ngx-bootstrap). | |
* Based on this library to enable drag support for an ng-bootstrap modal: https://github.com/mattxu-zz/ngb-modal-draggable | |
* | |
* Enable by adding the directive to the modal-header element, e.g.: | |
* | |
* <div class="modal-header" ngxModalDraggable> </div> | |
*/ | |
@Directive({ | |
selector: '[ngxModalDraggable]' | |
}) | |
export class NgxModalDraggableDirective implements AfterViewInit { | |
private modalElement: HTMLElement; | |
private topStart: number; | |
private leftStart: number; | |
private isDraggable: boolean; | |
private handleElement: HTMLElement; | |
constructor(public element: ElementRef) { | |
} | |
ngAfterViewInit() { | |
let element = this.element.nativeElement; | |
//only make the modal header draggable | |
this.handleElement = this.element.nativeElement; | |
//change cursor on the header | |
this.handleElement.style.cursor = 'pointer'; | |
//get the modal parent container element: that's the element we're going to move around | |
for (let level = 3; level > 0; level--) { | |
element = element.parentNode; | |
} | |
this.modalElement = element; | |
this.modalElement.style.position = 'relative'; | |
} | |
@HostListener('mousedown', ['$event']) | |
onMouseDown(event: MouseEvent) { | |
if (event.button === 2 || (this.handleElement && event.target !== this.handleElement)) { | |
return; // prevents right click drag | |
} | |
//enable dragging | |
this.isDraggable = true; | |
//store original position | |
this.topStart = event.clientY - Number(this.modalElement.style.top.replace('px', '')); | |
this.leftStart = event.clientX - Number(this.modalElement.style.left.replace('px', '')); | |
event.preventDefault(); | |
} | |
@HostListener('document:mouseup', ['$event']) | |
onMouseUp(event: MouseEvent) { | |
this.isDraggable = false; | |
} | |
@HostListener('document:mousemove', ['$event']) | |
onMouseMove(event: MouseEvent) { | |
if (this.isDraggable) { | |
//on moving the mouse, reposition the modal | |
this.modalElement.style.top = (event.clientY - this.topStart) + 'px'; | |
this.modalElement.style.left = (event.clientX - this.leftStart) + 'px'; | |
} | |
} | |
@HostListener('document:mouseleave', ['$event']) | |
onMouseLeave(event: MouseEvent) { | |
this.isDraggable = false; | |
} | |
} |
In case, when you have no 'modal-header' class and you have to put draggable directive to some element inside 'modal-content'. like in my case i have to put on my Title div. Use following snippet to achieve your goal.
//get the modal parent container element: that's the element we're going to move around
// for (let level = 3; level > 0; level--) {
// element = element.parentNode;
// }
element = element.closest('.modal');
Instead of using element = element.closest(.modal); We can use element = element.closest('.modal-content'); Because in my case .closest(.modal) returned the class with modal-header.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Great code. Helped a lot. I would suggest one improvement:
I have changed
onMouseDown
in a following way:And declare method searchParentNode:
This way you're able to activate drag also on children elements of modal-header which is useful if you put more elements than a simple text to a header.