I am working with Angular8 Drag and Drop and come across some problem
What is my concept and what I am doing
- Truck in which I drag and drop deliveries
- Deliveries in which I drag and drop packages this are working fine
I am using following JSON data structute(shown below) which is get updated with moveItemInArray
and transferArrayItem
function
trucks = [{
"..": '',
"Deliveries": [{
"..": '',
"Packages": [{
}, {}, {}, ....]
}, {}, {}, ....]
}, {}, {}, ....]
Everything works fine but I need some extra things to be applied with drag and drop that is,
I want a package to be directly dropped inside truck...so when a package is directly dropped into the truck I want to add a delivery object in that truck deliveries and then inside that delivery, I want to assign the drop package
I want delivery to be directly dropped inside the delivery...so when delivery is directly dropped I want to move all package of previous delivery packages to current delivery
I have tried a lot with different things but drag and drop get disturbed and miss behaves
Below are my ts and HTML template code
import { Component, Input, OnInit } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { ModelTruck } from '../../core/models/model-truck';
import { ModelDelivery } from '../../core/models/model-delivery';
import { ModelPackage } from '../../core/models/model-package';
@Component({
selector: 'app-manual',
templateUrl: './manual.component.html',
styleUrls: ['./manual.component.css']
})
export class ManualComponent implements OnInit {
@Input() packages: ModelPackage[];
@Input() trucks: ModelTruck[];
@Input() deliveries: ModelDelivery[];
/**
* Trucks inside work area
*/
workTrucks = [];
/**
* Deliveries drop inside trucks connected element IDs
*/
truckIds = ['no-trucks'];
/**
* Packages drop inside deliveries connected element IDs
*/
deliveryIds = ['no-delivery'];
/**
* Column from which we are applying filter
*/
column: any = 'Km';
/**
* Direction use for filter ASC or DESC
*/
direction = 1;
/**
* Choosed truck/delivery/package data
*/
choosed = {
'1': '-',
'2': '-',
'3': '-',
'4': '-',
'5': '-',
'6': '-',
'7': '-',
'8': '-',
'9': '-',
'10': '-',
'11': '-',
'12': '-',
'13': '-',
'14': '-',
'15': '-',
'16': '-',
'17': '-',
'18': '-',
'19': '-',
'20': '-',
'..': '..',
};
/**
* Initializing constructor
*/
ngOnInit() {
this._createConnectedIds();
this._calculateAllStuff();
}
/**
* Creating connected link Ids for the drag and drop elements
*/
_createConnectedIds() {
// For the deliveries to be drag and drop
for (let truck of this.trucks) {
this.truckIds.push(`truck-${truck.ID}`);
for (let delivery of truck.Deliveries) {
this.deliveryIds.push(`delivery-${delivery.ID}`);
}
}
// For the packages to be drag and drop
for (let delivery of this.deliveries) {
this.deliveryIds.push(`delivery-${delivery.ID}`);
}
}
/**
* Onchange sort by
*/
doSort(sort) {
this.direction = sort == 'ASC' ? 1 : -1;
}
/**
* Onchange filter by
*/
doFilter(filter) {
this.column = filter;
}
/**
* Event on drop the packages
*/
onPackageDrop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
this._calculateAllStuff();
}
/**
* Event on drop the deliveries
*/
onDeliveryDrop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
this._calculateAllStuff();
}
/**
* Event on drop the trucks
*/
onTruckDrop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
this._calculateAllStuff();
}
/**
* Calculate all the stuffs
* Related to weight, volume, cost and number of packages etc
*/
_calculateAllStuff() {
this._removeDeliveriesWithoutPackage();
this._calculateTrucksStuff();
this._calculateDeliveriesStuff(this.deliveries);
console.log('-----------------------');
console.log('Trucks Inside The List');
console.log(this.trucks);
console.log('Trucks Inside Work Area');
console.log(this.workTrucks);
}
/**
* Remove deliveries without package
*/
_removeDeliveriesWithoutPackage() {
// Remove deliveries not contains package (Deliveries area)
this.deliveries = (this.deliveries).filter(function(obj) {
return obj.Packages.length != 0;
});
// Remove deliveries not contains package (Work Area)
for( let truck of this.workTrucks ) {
truck.Deliveries = (truck.Deliveries).filter(function(obj) {
return obj.Packages.length != 0;
});
}
}
/**
* Calculate package related stuffs
* Related to weight, volume, cost and number of pieces etc
*/
_calculatePackagesStuff(packages) {
let packageStuffs = {
ActualWeightDry: packages.filter((obj) => obj.TypePackage === 'dry').length,
ActualWeightCold: packages.filter((obj) => obj.TypePackage === 'cold').length,
ActualWeight: 0,
ActualVolume: 0,
ActualCostMerchandise: 0,
NumberPackages: packages.length,
NumberPieces: 0
};
for( let item of packages ) {
packageStuffs.ActualWeight += item.ActualWeight;
packageStuffs.ActualVolume += item.ActualVolume;
packageStuffs.ActualCostMerchandise += item.ActualCostMerchandise;
packageStuffs.NumberPieces += item.NumberPieces;
}
return packageStuffs;
}
/**
* Calculate deliveries related stuffs
* Related to weight, volume, cost and number of pieces etc
*/
_calculateDeliveriesStuff(deliveries) {
let deliveryStuffs = {
MaxCostMerchadise: 0,
ActualWeight: 0,
ActualVolume: 0,
NumberDestinations: deliveries.length,
ActualCostMerchandise: 0,
NumberPackages: 0,
NumberPieces: 0,
Trip: 0
};
for( let delivery of deliveries ) {
deliveryStuffs.MaxCostMerchadise += delivery.MaxCostMerchadise;
deliveryStuffs.ActualWeight += delivery.ActualWeight;
deliveryStuffs.ActualVolume += delivery.ActualVolume;
deliveryStuffs.ActualCostMerchandise += delivery.ActualCostMerchandise;
deliveryStuffs.NumberPackages += delivery.Packages.length;
deliveryStuffs.NumberPieces += delivery.NumberPieces;
deliveryStuffs.Trip += delivery.Trip;
let packageStuffs = this._calculatePackagesStuff(delivery.Packages);
let keys = Object.keys(packageStuffs);
for( let key of keys ) {
delivery[key] = packageStuffs[key];
}
}
return deliveryStuffs;
}
/**
* Calculate trucks related stuffs for both work and in list
* Related to weight, volume, cost and number of pieces etc
*/
_calculateTrucksStuff() {
this._calculateForTruck(this.trucks);
this._calculateForTruck(this.workTrucks);
}
/**
* Calculate truck stuff
* Resulable code
*/
_calculateForTruck(trucks) {
for( let truck of trucks ) {
let deliveryStuffs = this._calculateDeliveriesStuff(truck.Deliveries);
let keys = Object.keys(deliveryStuffs);
for( let key of keys ) {
truck[key] = deliveryStuffs[key];
}
}
}
/**
* Recalculating time
*/
doRecalcTime() {
alert('Doing recalculate time[need to implement]');
}
/**
* Recalculating the order
*/
doRecalcOrder() {
alert('Doing recalculate order[need to implement]');
}
/**
* Choosed element
*/
choose(elem) {
this.choosed = elem;
}
/**
* Choosed element keys only
*/
choosedKeys() {
return Object.keys(this.choosed);
}
/**
* Check if object
*/
isItObject(elem) {
return elem instanceof Object;
}
}
<div class="main">
<div class="width-20 truck-lists">
<div class="sorting">
<div class="sort-filters">
<select (change)="doFilter($event.target.value)">
<option value="">Filter By</option>
<option value="TypeVehicle">TypeVehicle</option>
<option value="MaxWeight">MaxWeight</option>
<option value="MaxVolume">MaxVolume</option>
<option value="Km">Km</option>
<option value="Cost">Cost</option>
</select>
</div>
<div class="asc-or-desc" (change)="doSort($event.target.value)">
<select>
<option value="">Sort By</option>
<option value="ASC">ASC</option>
<option value="DESC">DESC</option>
</select>
</div>
</div>
<ul
cdkDropList
#truckArea="cdkDropList"
[cdkDropListData]="trucks"
[cdkDropListConnectedTo]="[workArea]"
(cdkDropListDropped)="onTruckDrop($event)">
<li
cdkDrag
*ngFor="let truck of trucks | orderBy: {property: column, direction: direction}"
class="truck-item"
(click)="choose(truck)">
<div class="truck-item-content">
{{ truck.TypeVehicle }}
#{{ truck.ID }} |
{{ truck.NumberDestinations }} Deliveries |
{{ truck.NumberPackages }} Packages |
{{ truck.Km }} Km |
${{ truck.Cost }}
</div>
<ol type="i">
<li *ngFor="let delivery of truck.Deliveries">
{{ delivery.State }}, {{ delivery.DestinationTR1 }}
</li>
</ol>
<span class="truck-size-tag">{{ truck.ID }}</span>
</li>
</ul>
</div>
<div class="width-60 truck-works">
<div class="truck-works-dashboard">
<ul
cdkDropList
#workArea="cdkDropList"
[cdkDropListData]="workTrucks"
[cdkDropListConnectedTo]="[truckArea]"
(cdkDropListDropped)="onTruckDrop($event)">
<li
cdkDrag
*ngFor="let truck of workTrucks"
class="truck-item truck-item-in-dashboard"
(click)="choose(truck)">
<div class="truck-item-content">
{{ truck.TypeVehicle }}
#{{ truck.ID }} |
{{ truck.NumberDestinations }} Deliveries |
{{ truck.NumberPackages }} Packages |
{{ truck.Km }} Km |
${{ truck.Cost }}
</div>
<div class="truck-row">
<div class="only-deliveries">
<ul
cdkDropList
[cdkDropListData]="truck.Deliveries"
cdkDropListOrientation="horizontal"
[cdkDropListConnectedTo]="truckIds"
id="truck-{{ truck.ID }}"
(cdkDropListDropped)="onDeliveryDrop($event)">
<li
cdkDrag
*ngFor="let delivery of truck.Deliveries"
class="delivery-item"
(click)="$event.stopPropagation(); choose(delivery)">
<div class="delivery-name">
{{ delivery.State }} - {{ delivery.DestinationTR1 }}
</div>
<div class="delivery-time">
{{ delivery.Delivery }}
</div>
<ul
cdkDropList
[cdkDropListData]="delivery.Packages"
[cdkDropListConnectedTo]="deliveryIds"
cdkDropListOrientation="horizontal"
(cdkDropListDropped)="onPackageDrop($event)"
id="delivery-{{ delivery.ID }}">
<li
cdkDrag
*ngFor="let package of delivery.Packages"
[ngClass]="package.Type == 'Urgent' ? 'package-item urgent' : 'package-item'"
(click)="$event.stopPropagation(); choose(package)">
Pack #{{ package.ID }}<br>
{{ package.Type }}
</li>
</ul>
</li>
</ul>
</div>
<div class="only-dashboard">
<table>
<thead>
<tr>
<th>Restriction</th>
<th>Kg</th>
<th>m3</th>
<th>$</th>
<th>Access</th>
<th>Minutes</th>
<th>Incomp</th>
</tr>
</thead>
<tbody>
<tr>
<th>Actual</th>
<td>{{ truck.ActualWeight }}</td>
<td>{{ truck.ActualVolume }}</td>
<td>${{ truck.ActualCostMerchandise }}</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<th>Max</th>
<td>{{ truck.MaxWeight }}</td>
<td>{{ truck.MaxVolume }}</td>
<td>${{ truck.MaxCostMerchadise }}</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<th>Available</th>
<td>
{{ truck.MaxWeight - truck.ActualWeight }}
</td>
<td>
{{ truck.MaxVolume - truck.ActualVolume }}
</td>
<td>
${{ truck.MaxCostMerchadise - truck.ActualCostMerchandise }}
</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<th>%Available</th>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
<td>-</td>
</tr>
</tbody>
</table>
</div>
</div>
<span class="truck-size-tag">{{ truck.ID }}</span>
</li>
</ul>
</div>
<div class="no-truck-deliveries">
<h4>No Truck</h4>
<ul
cdkDropList
[cdkDropListData]="deliveries"
cdkDropListOrientation="horizontal"
[cdkDropListConnectedTo]="truckIds"
(cdkDropListDropped)="onDeliveryDrop($event)"
id="no-trucks"
class="no-truck">
<li
cdkDrag
*ngFor="let delivery of deliveries"
class="delivery-item"
(click)="choose(delivery)">
<div class="delivery-name">
{{ delivery.State }} - {{ delivery.DestinationTR1 }}
</div>
<div class="delivery-time">
{{ delivery.Delivery }}
</div>
<ul
cdkDropList
[cdkDropListData]="delivery.Packages"
[cdkDropListConnectedTo]="deliveryIds"
cdkDropListOrientation="horizontal"
(cdkDropListDropped)="onPackageDrop($event)"
id="delivery-{{ delivery.ID }}">
<li
cdkDrag
*ngFor="let package of delivery.Packages"
[ngClass]="package.Type == 'Urgent' ? 'package-item urgent' : 'package-item'"
(click)="$event.stopPropagation(); choose(package)">
Pack #{{ package.ID }}<br>
{{ package.Type }}
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="width-20 truck-datas">
<div class="action-buttons">
<button class="btn">Import</button>
<button class="btn">Export</button>
</div>
<div class="element-datasets">
<table>
<tr *ngFor="let key of choosedKeys()">
<th [hidden]="isItObject(choosed[key])">{{ key }}</th>
<td [hidden]="isItObject(choosed[key])">{{ choosed[key] }}</td>
</tr>
</table>
</div>
<div class="action-buttons">
<button class="btn" (click)="doRecalcTime()">Recalculate Time</button>
<button class="btn" (click)="doRecalcOrder()">Recalculate Order</button>
</div>
</div>
</div>
I think you should implement mentioned scenario's based on the type of
event.container.data
.So for 1. A package to be directly dropped inside truck:
In pseudo code:
And for 2. Delivery in delivery
Seems like something you can use Typescripts
instanceof
for. https://www.typescriptlang.org/docs/handbook/advanced-types.html#instanceof-type-guards