In a world full of visually appealing dashboards, the real challenge lies in making them customisable enough to meet your users individual needs. While many dashboards are pretty, they often lack the flexibility for user-centric interaction. In this first article of the Drag. Drop. Engage. series, well take the first step toward building an interactive Angular dashboard from scratch, starting with a basic draggable directive. This foundation will set the stage for a dashboard users can tailor to maximise its value and functionality.
To follow the article, you should be familiar with Angular and TypeScript, understand Angular Directives, and have an Angular development environment set up.
So, let's begin by creating the draggable
directive.
ng generate directive draggable
Before initialising the directive, lets look at the events and attributes we will set.
Draggable : The draggable
attribute informs your browser whether this element can be moved.
Drag Start : The dragstart
event is issued whenever we move an HTML element marked with draggable
.
Position : The position absolute style allows us to drop
the HTML anywhere on the page.
Drag Over : The dragover
event is fired when a draggable
element is above a valid drop
target.
Drop : The drop
event is fired once we release the mouse above a valid drop
target.
/**
* Constructor
* Initializes styles, attributes, and event listeners for the element
* @param element Injected reference to the element this directive is attached to
*/
constructor(private element: ElementRef) {
this.element.nativeElement.addEventListener('dragstart',
this.dragStart.bind(this)); // Add event listener for dragstart
this.element.nativeElement.setAttribute('draggable', 'true'); // Make the element draggable
this.element.nativeElement.style.position = 'absolute'; // Set the position to absolute document.addEventListener('dragover',
this.dragOver.bind(this)); // Add event listener for dragover
document.addEventListener('drop', this.drop.bind(this)); // Add event listener for drop
}
With the element and the document being able to listen for the correct events, we can continue to implement the first method: dragStart
. This method stores the offset between the top left corner of our draggable
element and the position we clicked.
private _offset: { x: number, y: number } = { x: 0, y: 0 };
/**
* DragStart event handler * Calculates the offset of the mouse pointer from the top-left corner of the element for correct dropping
* @param event DragEvent
*/
private dragStart(event: DragEvent): void {
let elementPos = this.element.nativeElement.getBoundingClientRect(); // Get the position of the element
this._offset = { x: elementPos.left - event.clientX, y: elementPos.top - event.clientY }; // Calculate the offset
}
The dragOver
method is called whenever the draggable
element is above a valid drop
target. However, we want to be able to drop the element anywhere. To achieve this, we need to cancel the events default behaviour as we have no valid drop
target.
/**
* DragOver event handler
* Prevents the default behaviour of the event to allow dropping the element anywhere
* @param event DragEvent
*/
private dragOver(event: DragEvent): void {
event.preventDefault();
}
Lastly, we implement the drop
method. Once again, we must cancel the default behaviour to ensure the drop
is successful. Now, we just need to update the position of the draggable
element. To do this, we add the _offset
to the elements current position. This ensures we drop the draggable
element relative to the mouse position, just as we picked it up.
/**
* Drop event handler
* Drops the element, updating its position to the mouse pointer's position
* @param event DragEvent
*/
private drop(event: DragEvent): void {
event.preventDefault();
let x = event.clientX + this._offset.x; // Add the offset to the x position to get the correct position
let y = event.clientY + this._offset.y; // Add the offset to the y position to get the correct position
this.element.nativeElement.style.left = x + 'px'; // Set the new x position this.element.nativeElement.style.top = y + 'px'; // Set the new y position
}
With the directive
wrapped-up, we can use it. Open the app.component.html
file and add some valid HTML. I use a Bootstrap Card, just to make it look nice.
💡 Depending on your Angular project, your directive might be called appDraggable.
<div class="card col-2 position-absolute" ngDraggable>
<div class="card-header"> Drag and Drop </div>
<div class="card-body"> </div>
</div>
And here is the whole project up and running.
With the foundation laid for creating a basic draggable directive in Angular, you've taken the first step toward building a more interactive and customisable dashboard. Now, it's time to put this knowledge into practice. Try implementing this example in your own project, tweak the code to see how it behaves, and experiment with additional features or improvements. If you'd like, feel free to fork this example and share your variations or enhancements.
Don't hesitate to reach out with questions, insights, or suggestions. Stay tuned for the next article in the series, where we'll continue to elevate your drag-and-drop dashboard by building a visual CSS grid!
Top comments (0)