How to Handle Drag and Drop Events in Angular ListBox

Created: 21 Jan 2019

Whenever an item is dragged within the ListBox component, based on user action several drag and drop events can occur. You can handle these events in your code and provide additional conditions that may alter the default drag and drop functionality. In this article you will learn about all drag drop events that are supported and how to handle them in different situations.

ListBox component is part of IntegralUI Web
a suite of UI Components for development of web apps

If you have any questions, don't hesitate to contact us at support@lidorsystems.com

As item is dragged in the ListBox, the list on the right side will display event when fired. As explained in sections below, when item is dragged over target item "Gladiator", it can only drop below it. In other cases you can freely reorder items.

The list on the right displays events that fires during drag drop. You can see the event name, dragged item, target item and drop position. If the event fires multiple times subsequently, it can happen with drag over event, a counter will appear left from the event name stating how many times that event fired. In addition, if an event is cancelled, the event log will add 'cancelled' in red, next to the event message.

Drag and Drop Events that are Supported in Angular ListBox

During item drag and drop operation, several events are fired that you can handle in your code. Here is the list of supported events:

  • dragEnter - fires when mouse cursor enters the ListBox space for the first time
  • dragDrop - fires when dragged item drops
  • dragLeave - fires when mouse cursor leaves the ListBox space
  • dragOver - fires when mouse cursor is over target item or component

By adding handlers for these events in your code, you can intercept the drag drop operation and change its course using custom conditions.

Drag Drop Event Data

The drag and drop event data contains information that you can use in your code to customize the drag drop operations in whole and create the best solution for your application requirements. Depending on the event, a different data is included. In general, here is a list of data fields available:

  • action - specifies whether item is moved or copied
  • cancel - determines whether drag drop is cancelled
  • dragItem - specifies an item(s) that is dragged
  • dropPos - specifies position at which dragged item can drop
    • 1 - item will drop above target item
    • 2 - item will drop below target item
    • -1 - item will drop at the end of item collection of target component
  • event - general HTML5 drag drop event data settings
  • isDropAllowed - determines whether item can drop
  • mousePos - position of mouse cursor in page coordinates
  • sourceCtrl - a reference to a component from which drag drop operation has started
  • targetCtrl - a reference to a component over which dragged item is dropped
  • targetItem - specifies the item over which dragged item is positioned or dropped

How to Set Conditions on Drag Over

Whenever item is dragged over another item or a different ListBox component, the dragOver event will fire. You can create a handler function for this event, where you can set custom conditions that will allow or not drops of dragged item.

For example, let's say that if the target item is "Gladiator" and you want the dragged item to only drop below it. In this case, at first you need to check whether there is a target item and the current drop position:

listDragOver(e: any){
    if (e.dropPos == 1 && e.targetItem && e.targetItem.text == 'Gladiator')
        e.cancel = true;
}
                            
<div class="app-block" #application>
    <iui-listbox [appRef]="applicationRef" [items]="items" [controlStyle]="lBoxStyle" [allowDrag]="true" (dragEnter)="listDragEnter($event)" (dragOver)="listDragOver($event)" (dragLeave)="listDragLeave($event)" (dragDrop)="listDragDrop($event)" #listbox>
        <iui-listitem *ngFor="let item of items" [controlStyle]="lboxItemStyle" [allowAnimation]="true">  
            <div class="lbox-dd-evnt-item-content">
                <span class="lbox-dd-evnt-icons {{item.icon}}"></span>
                <span class="lbox-dd-evnt-title">{{item.text}}</span>
            </div>
        </iui-listitem>
    </iui-listbox>
    <div class="app-event-block">
        <button (click)="clearEventLog()">Clear</button>
        <p>Event log:</p>
        <ul class="app-event-log">
            <li *ngFor="let ev of eventLog">
                <div><span *ngIf="ev.count" class="app-event-count">{{ev.count}}</span> <span class="app-event-name">{{ev.name}}</span></div>
                <div>{{ev.info}}<span class="app-event-value"> at position: {{ev.position}}</span> <span *ngIf="ev.cancelled" class="app-event-cancelled">cancelled</span></div>
            </li>
        </ul>
    </div>
</div>
                            

As you can see from code, if the drop position is 1, it means the dragged item is about to drop above the target item, which we don't want. To prevent it, just set the cancel field to true.

Related: How to Move Multiple Items with Drag and Drop

The dragged item can still drop over this target item, but only if it is over the lower part of the target space, that is with drop position 2 which means below the target item.

Note Note This is another way to prevent drops over target items, instead of using the allowDrop field of the item object.

How to Validate Position on Item Drop

When item is dropped the dragDrop event will fire. This event concludes the drag and drop operation and it's called once the drop is completed. You can still cancel this event and prevent item from dropping, if some action on your side is not yet completed.

Instead of preventing item to drop above the target item within the dragOver event handler (see above), you can do it in dragDrop event handler. In this case, you can check the drop position and if it is 1, cancel the event and proceed with placing the dragged item below the target item.

listDragDrop(e: any){
    if (e.dropPos == 1 && e.targetItem){
        e.cancel = true;

        e.targetCtrl.insertItemAfter(e.dragItem, e.targetItem);
    }
}
                            
<div class="app-block" #application>
    <iui-listbox [appRef]="applicationRef" [items]="items" [controlStyle]="lBoxStyle" [allowDrag]="true" (dragEnter)="listDragEnter($event)" (dragOver)="listDragOver($event)" (dragLeave)="listDragLeave($event)" (dragDrop)="listDragDrop($event)" #listbox>
        <iui-listitem *ngFor="let item of items" [controlStyle]="lboxItemStyle" [allowAnimation]="true">  
            <div class="lbox-dd-evnt-item-content">
                <span class="lbox-dd-evnt-icons {{item.icon}}"></span>
                <span class="lbox-dd-evnt-title">{{item.text}}</span>
            </div>
        </iui-listitem>
    </iui-listbox>
    <div class="app-event-block">
        <button (click)="clearEventLog()">Clear</button>
        <p>Event log:</p>
        <ul class="app-event-log">
            <li *ngFor="let ev of eventLog">
                <div><span *ngIf="ev.count" class="app-event-count">{{ev.count}}</span> <span class="app-event-name">{{ev.name}}</span></div>
                <div>{{ev.info}}<span class="app-event-value"> at position: {{ev.position}}</span> <span *ngIf="ev.cancelled" class="app-event-cancelled">cancelled</span></div>
            </li>
        </ul>
    </div>
</div>
                            

In this way, you can intercept the drag and drop operation and in both cases of drop position (above or below), the dragged item will be placed always below the target item.

How to Cancel Drag and Drop Event

In similar way like explained above cancelling item drops above the target item, you can cancel the drag and drop in all cases, for the specific item or for all items.

For example, if you set the cancel field to false, without any conditions the item can't drop. In similar way like if the allowDrop property for ListBox component is set to false.

The more suitable case for cancelling a drop event is to set it if some action required was not yet completed, like data loading is not yet finished. In addition, it is useful to cancel the item drop in whole when you want to change the item data on your own.

listDragDrop(e: any){
   e.cancel = true;

    if (e.dragItem){
        // Remove the item from the source component
        e.sourceCtrl.removeItem(e.dragItem);

        // Change the item text
        e.dragItem.text = 'New Item';

        // Add the item to target component at location, depending on drop position
        switch (e.dropPos){
            case 1: // Above the target item
                e.targetCtrl.insertItemBefore(e.dragItem, e.targetItem);
                break;

            case 2: // Below the target item
                e.targetCtrl.insertItemAfter(e.dragItem, e.targetItem);
                break;

            default: // At the end of the list
                e.targetCtrl.addItem(e.dragItem);
                break;
        }

        e.targetCtrl.updateLayout();
    }
}
                            

Related: How to Copy Item with Drag and Drop

For example, cancel the event and change the item text to 'New Item'. Therefore, any item that drops will have the same name. You can proceed with custom actions to add the dropped item to the new component at location specified by the drop position.

Note If the drag and drop operation is set to 'move', you also need to remove the dropped item from the source component.

Conclusion

IntegralUI ListBox component for Angular accompanies few drag and drop events. By handling these events in your code, you can change the item drag and drop in part or completely using custom conditions. In some cases, using the event data you may even cancel the whole drag and drop operation.

The ListBox component is part of IntegralUI Web.

Newsletter


Sign-up to our newsletter and you will receive news on upcoming events, latest articles, samples and special offers.
Name: Email: *
*By checking this box, I agree to receive a newsletter from Lidor Systems in accordance with the Privacy Policy. I understand that I can unsubscribe from these communications at any time by clicking on the unsubscribe link in all emails.