PrimeNG Listbox: How to allow re-ordering of items via drag and drop?

Viewed 2725

The title says it all. I have a listbox and I would like to be able to reorder the items displayed via drag and drop. The model should be updated as well of course. I understand I need to use the pDraggable and pDroppable directives but so far I have only managed to make my list items 'draggable' without being able to 'drop' them above or below other list items.

Also I'm not sure how to use the events provided to update my model once the user drops an item. Finally I would like to have an icon on the left side of each item and that should be the only part of list item that is 'draggable' (with the cursor changing into a hand).

I'm not attaching any code since a listbox is a very simple thing to make. Finally I'm using PrimeNG v9.0.

Thank you in advance!

1 Answers

Ok so I found it. First of all there is already a PrimeNG component that does the job: OrderList. However this component adds buttons to the left or right of the list and these buttons cannot be hidden (which is stupid). So here is how to do it with a simple Listbox:

  1. Add a let-index="index" code in your ng-template. You need the index because you have to update your model programmatically.
  2. Declare both the pDraggable and pDroppable directives (use the same name: in my case its gens) in the <div> right below the ng-template.
  3. In the same div add the methods (onDragStart) and (onDrop). Pass the index to both of these methods.
  4. Finally define a dragHandle (optional). In my case the drag handle is the bars icon

HTML:

<p-listbox [options]="generals" [(ngModel)]="selectedGeneral" (onChange)="onChange($event.value)"
    [listStyle]="{'height':'282px'}" [style]="{ width: '235px', height: '100%' }">
    <ng-template let-general let-index="index" pTemplate="item">
        <div class="ui-helper-clearfix" pDraggable="gens" pDroppable="gens" dragHandle=".barsHandle" (onDragStart)="onDragStart(index)" (onDrop)="onDrop(index)">
            <i class="fa fa-bars barsHandle"></i>
            <img [src]="getGenIcon(general.value)" style="margin-right: 5px;">
            <span style="vertical-align: middle;">{{general.label}}</span>
        </div>
    </ng-template>
</p-listbox>

TS:

onDragStart(index: number) {
    this.startIndex = index;
}

onDrop(dropIndex: number) {
    const general = this.generals[this.startIndex]; // get element
    this.generals.splice(this.startIndex, 1);       // delete from old position
    this.generals.splice(dropIndex, 0, general);    // add to new position
}
Related