Precap:
Part-1:
Part-2:
Discussed on cdkDropListConnectedTo directive.
Discussed on cdkDropListData directive.
Discussed on transferArrayItem method.
Discussed on cdkDropListGroup directive.
cdkDropListEnterPredicate Directive:
A predicate is a function that returns boolean results either true or false. cdkDropListeEnterPredicate directive accepts a predicate as an input. So on dragging and dropping of an item into a container will be accepted based on predicate output, if the predicate returns true dropped item will be accepted by the container or if the predicate returns false dropped item will be rejected by the container. So by using the cdkDropListEnterPredicate directive, we can control the items that will be dragged and dropped onto the container.
Sample Example To Control Items Drag And Drop Using cdkDropListEnterPredicate Directive:
Let's first implement a sample of dragging and dropping off items between containers and later we will add cdkDropListEnteterPredicate directive.
src/app/cdkPredicate/cdk.predicate.sample.component.css:
.my-container { width: 400px; max-width: 100%; margin: 0 25px 25px 0; display: inline-block; vertical-align: top; } .my-list { border: solid 1px #ccc; min-height: 60px; background: white; border-radius: 4px; overflow: hidden; display: block; } .my-box { padding: 20px 10px; border-bottom: solid 1px #ccc; color: rgba(0, 0, 0, 0.87); display: flex; flex-direction: row; align-items: center; justify-content: space-between; box-sizing: border-box; cursor: move; background: white; font-size: 14px; } .cdk-drag-preview { box-sizing: border-box; border-radius: 4px; box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); } .cdk-drag-placeholder { opacity: 0; } .cdk-drag-animating { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } .my-box:last-child { border: none; } .my-list.cdk-drop-list-dragging .my-box:not(.cdk-drag-placeholder) { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); }src/app/cdkPredicate/cdk.predicate.sample.component.html:
<div class="my-container"> <h2>All Students</h2> <div #allStudentsContainer="cdkDropList" cdkDropList [cdkDropListData]="allStudents" [cdkDropListConnectedTo]="[failedStudentsContainer]" class="my-list" (cdkDropListDropped)="drop($event)" > <div class="my-box" *ngFor="let student of allStudents" [cdkDragData]="student" cdkDrag > {{ student.Name }} -----> {{student.Result}} </div> </div> </div> <div class="my-container"> <h2>Falied Students</h2> <div #failedStudentsContainer="cdkDropList" cdkDropList [cdkDropListData]="failedStudents" [cdkDropListConnectedTo]="[allStudentsContainer]" class="my-list" (cdkDropListDropped)="drop($event)" > <div class="my-box" *ngFor="let student of failedStudents" cdkDrag [cdkDragData]="student" > {{ student.Name }} ----> {{student.Result}} </div> </div> </div>src/app/cdkPredicate/cdk.predicate.sample.component.ts:
import { Component } from '@angular/core'; import { CdkDragDrop, moveItemInArray, transferArrayItem, } from '@angular/cdk/drag-drop'; @Component({ selector: 'cdk-predicate-sample', templateUrl: 'cdk.predicate.sample.component.html', styleUrls: ['cdk.predicate.sample.component.css'], }) export class CdkPredicateSampleComponent { allStudents = [ { Name: 'Naveen', Result: 'Failed' }, { Name: 'Ramanajee', Result: 'Pass' }, { Name: 'Rama Krishna', Result: 'Pass' }, { Name: 'Gopi', Result: 'Pass' }, { Name: 'Leela Narasimha', Result: 'Pass' }, { Name: 'Hemanth Kumar', Result: 'Failed' } ]; failedStudents = []; drop(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 ); } } }src/app/app.component.html:
<cdk-predicate-sample></cdk-predicate-sample>src/app/app.module.ts:
import { CdkPredicateSampleComponent } from './cdkPredicate/cdk.predicate.sample.component'; @NgModule({ declarations: [ CdkPredicateSampleComponent ] }) export class AppModule {} // code hidden for display purposeNow run the application and output shows as below.
Now let's add a restriction on 2nd container to accept only failed students. so to achieve this we can use cdkDropListEnterPredicate.
Let's start by creating a function that returns the boolean value and this function will be used as a predicate for the cdkDropListEnterPredicate.
src/app/cdkPredicate/cdk.predicate.sample.component.ts:
import { Component } from '@angular/core'; import { CdkDrag } from '@angular/cdk/drag-drop'; @Component({ selector: 'cdk-predicate-sample', templateUrl: 'cdk.predicate.sample.component.html', styleUrls: ['cdk.predicate.sample.component.css'], }) export class CdkPredicateSampleComponent { onlyFailedStudents(item:CdkDrag){ return item.data["Result"] === "Failed"; } // code hidden for display purpose. }
- #L3 at this CdkDrag object type loaded from '@angular/cdk/drag-drop' package
- #L13-L15 at these lines created method 'onlyFailedStudents', this method will be used as predicate value for the cdkDropListEnterPredicate directive. It has an input parameter of type 'CdkDrag' which gives all the information about the item on dragging. So in this example, this predicate or method returns a boolean value true for only items that of failed students. So this will restrict the dragging of all elements into the container that has cdkDropListEnterPredicate with 'onlyFailedStudents' as input predicate.
src/app/cdkPredicate/cdk.predicate.sample.component.html:
<div class="my-container"> <h2>All Students</h2> <div #allStudentsContainer="cdkDropList" cdkDropList [cdkDropListData]="allStudents" [cdkDropListConnectedTo]="[failedStudentsContainer]" class="my-list" (cdkDropListDropped)="drop($event)" > <div class="my-box" *ngFor="let student of allStudents" [cdkDragData]="student" cdkDrag > {{ student.Name }} -----> {{student.Result}} </div> </div> </div> <div class="my-container"> <h2>Falied Students</h2> <div #failedStudentsContainer="cdkDropList" cdkDropList [cdkDropListData]="failedStudents" [cdkDropListConnectedTo]="[allStudentsContainer]" class="my-list" (cdkDropListDropped)="drop($event)" [cdkDropListEnterPredicate]="onlyFailedStudents" > <div class="my-box" *ngFor="let student of failedStudents" cdkDrag [cdkDragData]="student" > {{ student.Name }} ----> {{student.Result}} </div> </div> </div>#L34 at this line cdkDropListEnterPredicate added on 2nd container with 'onlyFailedStudent' predicate as input.
Now run the application and 2nd container only accepts failed students on drag and then output shows as below.
cdkDropListOrientation Directive:
cdkDropListOrientation directive defines items to render vertically or horizontally. By default, cdkDropList directive renders items vertically. So by using the cdkDropListOrientation directive, we can define explicitly to render items vertically or horizontally.
Example Using cdkDropListOrientation Directive:
Let's implement a sample application that renders items horizontally using the cdkDropListOrientation directive.
src/app/cdkOrientationSample/cdk.orientation.sample.css:
.my-list { width: 1000px; max-width: 100%; border: solid 1px #ccc; min-height: 60px; display: flex; flex-direction: row; background: white; border-radius: 4px; overflow: hidden; } .my-box { padding: 20px 10px; border-right: solid 1px #ccc; color: rgba(0, 0, 0, 0.87); display: flex; flex-direction: row; align-items: center; justify-content: space-between; box-sizing: border-box; cursor: move; background: white; font-size: 14px; flex-grow: 1; flex-basis: 0; } .cdk-drag-preview { box-sizing: border-box; border-radius: 4px; box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12); } .cdk-drag-placeholder { opacity: 0; } .cdk-drag-animating { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } .my-box:last-child { border: none; } .my-list.cdk-drop-list-dragging .my-box:not(.cdk-drag-placeholder) { transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); }src/app/cdkOrientationSample/cdk.orientation.sample.ts:
import { Component } from '@angular/core'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; @Component({ selector:'cdk-orientation', templateUrl:'cdk.orientation.sample.html', styleUrls:['cdk.orientation.sample.css'] }) export class CdkOrientationSample { fruits=[ "Apple", "Grapes", "Banana", "Mango", "Pine apple" ]; drop(event:CdkDragDrop<string>){ moveItemInArray(this.fruits, event.previousIndex, event.currentIndex); } }src/app/cdkOrientationSample/cdk.orientation.sample.html:
<div cdkDropList cdkDropListOrientation="horizontal" class="my-list" (cdkDropListDropped)="drop($event)"> <div class="my-box" *ngFor="let fruit of fruits" cdkDrag>{{fruit}}</div> </div>#L1 at this line cdkDropListOrientation directive used and its value declared as 'horizontal'.
Now run the application, items rendered horizontally, and output shows as below.
Wrapping Up:
Hopefully, I think this article delivered some useful information on the Drag and Drop Angular Material CDK. I love to have your feedback, suggestions, and better techniques in the comment section below.
Hi There,
ReplyDeleteIt's very nice explanation of drag and drop. Here my understanding is that instead of drag and drop with static data. Is it possible to drag and drop component and render at runtime?
Thanks,
Vinay