tunneling
tunneling

Reputation: 527

Angular Material Drag and Drop - Different Object Types

I'm building a shopping cart and would like to be able to drag and drop items from a list of Products into the Cart and add them to the "items" of the Cart. The Products are more like technical services, therefore I didn't want to use the term Services... so you'll see "hours" in the models.

I'm able to render the two lists, and drag and drop Products into the Cart.. but of course, the Cart contains CartItems which contains a "snapshot" of the Product. Obviously this doesn't work as desired.

My question is: How can I do this with the Drag and Drop?

I also recognize that my entire approach to this problem may be wrong. I'm open to any recommendations.

Rather than post a bunch of screenshots and code, here's a link to the app :) on Stackblitz:

EDIT: This stackblitz is functioning properly

drag-drop-test

Models are as follows:

export class Cart {
    id: string;
    title: string;
    items?: CartItem[];
}
export class CartItem {
    qty: number;
    hours: number;
    product: Product;
}
export class Product {
    id: string;
    title: string;
    dhours: number; // default hours
}

Upvotes: 3

Views: 5455

Answers (2)

Eliseo
Eliseo

Reputation: 57929

the cdkdrag and drop it's not magic. it makes easy manage two arrays of object(*) in a visual manner. but it's only this: you has two arrays that show in a *ngFor, and you change the arrays (or not) dragging elements. After finished the drag and drop, Angular repaint the two *ngFors

If you take a look to the event cdkDrapDrop you see that this has as properties (among others):

  1. container: Container in which the item was dropped. (container.data is the array associated to the cdkDropList in witch the item was dropped)
  2. currentIndex: Current index of the item.
  3. previousContainer: Container from which the item was picked up. (previousContainer.data is the array associated to the cdkDropList in witch the item was picked up)
  4. previousIndex: Index of the item when it was picked up

it's not necesary use the function transferArrayItems, you can use, e.g.

drop(event: CdkDragDrop<any>) {
    //get the data asociated to the item dragged
    const dragItem=previousContainer[previousIndex]
    //create an object using this data
    const addItem={id: dragItem.id,
                   title: dragItem.id,
                   dhours: dragItem.dhours,
    //add to the array of the data where we dropped the object
    container.data.splice(1, 0, addItem);
}

And maintain untouched the array array associated to the cdkDropList in witch the item was picked up. After we dropped the object, Angular repaint the two "list" with the data of the arrays

(*)Updated: well, really I was talking about array as [cdkDropListData], but nobody forbide us that the data was a simple string or a simple object. Some like

<div cdkDropList [cdkDropListData]="{name:'Name'}"
            [cdkDropListConnectedTo]="[cdkBoard]" 
            (cdkDropListDropped)="drop($event)" 
            cdkDropListSortingDisabled="true">
    <div cdkDrag>
         Drag me!
         <div *cdkDragPlaceholder></div>
    </div>
</div>

makes that in the drop event previousContainer.data was the object {name:'Name'}

Upvotes: 2

Ashish
Ashish

Reputation: 1121

You will have convert your product to cartItem before moving it to other array.

const cartItem = [{
    qty: null,
    hours: null,
    product: event.previousContainer.data[event.previousIndex]
}]
transferArrayItem<CartItem>(cartItem,
    event.container.data,
    event.previousIndex,
    event.currentIndex);
event.previousContainer.data.splice(event.previousIndex, 1); // You will have to remove previous item yourself

Update stackblitz https://stackblitz.com/edit/github-4t79ak I did only for moving from product list to cart item, you can try it for other direction.

Upvotes: 1

Related Questions