Skip to content

docs(drag-drop): add docs and live examples #12794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 118 additions & 1 deletion src/cdk/drag-drop/drag-drop.md
Original file line number Diff line number Diff line change
@@ -1 +1,118 @@
# TODO
The `@angular/cdk/drag-drop` module provides you with a way to easily and declaratively create
drag-and-drop interfaces, with support for free dragging, sorting within a list, transferring items
between lists, animations, touch devices, custom drag handles, previews, and placeholders,
in addition to horizontal lists and locking along an axis.

### Getting started
Start by importing `DragDropModule` into the `NgModule` where you want to use drag-and-drop
features. You can now add the `cdkDrag` directive to elements to make them draggable. When
outside of a `<cdk-drop>` element, draggable elements can be freely moved around the page.
You can add `<cdk-drop>` elements to constrain where elements may be dropped.

<!-- example(cdk-drag-drop-overview) -->

### Reordering lists
Adding `<cdk-drop>` around a set of `cdkDrag` elements groups the draggables into a
reorderable collection. Items will automatically rearrange as an element moves. Note
that this will *not* update your data model; you can listen to the `dropped` event to
update the data model once the user finishes dragging.

<!-- example(cdk-drag-drop-sorting) -->

### Transferring items between lists
The `<cdk-drop>` component supports transferring dragged items between connected drop zones.
You can connect one or more `<cdk-drop>` instances together by setting the `connectedTo`
property.

<!-- example(cdk-drag-drop-connected-sorting) -->

Note that `connectedTo` works both with a direct reference to another `<cdk-drop>`, or by
referencing the `id` of another drop container:

```html
<!-- This is valid -->
<cdk-drop #listOne [connectedTo]="[listTwo]"></cdk-drop>
<cdk-drop #listTwo [connectedTo]="[listOne]"></cdk-drop>

<!-- This is valid as well -->
<cdk-drop id="list-one" [connectedTo]="['list-two']"></cdk-drop>
<cdk-drop id="list-two" [connectedTo]="['list-one']"></cdk-drop>
```

### Attaching data
You can associate some arbitrary data with both `cdkDrag` and `<cdk-drop>` by setting
`cdkDragData` or `data`, respectively. Events fired from both directives include this data,
allowing you to easily identify the origin of the drag or drop interaction.

```html
<cdk-drop [data]="list" *ngFor="let list of lists" (dropped)="drop($event)">
<div cdkDrag [cdkDragData]="item" *ngFor="let item of list"></div>
</cdk-drop>
```

### Styling
The `cdkDrag` and `<cdk-drop>` directive include only those styles strictly necessary for
functionality. The application can then customize the elements by styling CSS classes added
by the directives:

| Selector | Description |
|---------------------|--------------------------------------------------------------------------|
| `.cdk-drop` | Corresponds to the `<cdk-drop>` container. |
| `.cdk-drag` | Corresponds to a `cdkDrag` instance. |
| `.cdk-drag-preview` | This is the element that will be rendered next to the user's cursor as they're dragging an item in a sortable list. By default the element looks exactly like the element that is being dragged. |
| `.cdk-drag-placeholder` | This is element that will be shown instead of the real element as it's being dragged inside a `<cdk-drop>`. By default this will look exactly like the element that is being sorted. |
| `.cdk-drop-dragging` | A class that is added to `<cdk-drop>` while the user is dragging an item. |

### Animations
The drag-and-drop module supports animations both while sorting an element inside a list, as well as
animating it from the position that the user dropped it to its final place in the list. To set up
your animations, you have to define a `transition` that targets the `transform` property. The
following classes can be used for animations:

* `.cdk-drag` - If you add a `transition` to this class, it'll animate as the user is sorting
through a list.
* `.cdk-drag-animating` - This class is added to a `cdkDrag` when the user has stopped dragging.
If you add a `transition` to it, the CDK will animate the element from its drop position to
the final position inside the `<cdk-drop>` container.

Example animations:

```css
/* Animate items as they're being sorted. */
.cdk-drop-dragging .cdk-drag {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

/* Animate an item that has been dropped. */
.cdk-drag-animating {
transition: transform 300ms cubic-bezier(0, 0, 0.2, 1);
}
```

### Customizing the drag area using a handle
By default, the user can drag the entire `cdkDrag` element to move it around. If you want to
restrict the user to only be able to do so using a handle element, you can do it by adding the
`cdkDragHandle` directive to an element inside of `cdkDrag`. Note that you can have as many
`cdkDragHandle` elements as you want:

<!-- example(cdk-drag-drop-handle) -->

### Customizing the drag preview
When a `cdkDrag` element is picked up, it will create a preview element visible while dragging.
By default, this will be a clone of the original element positioned next to the user's cursor.
This preview can be customized, though, by providing a custom template via `*cdkDragPreview`:

<!-- example(cdk-drag-drop-custom-preview) -->

### List orientation
The `cdk-drop` component assumes that lists are vertical by default. This can be
changed by setting the `orientation` property to `"horizontal".

<!-- example(cdk-drag-drop-horizontal-sorting) -->

### Restricting movement along an axis
By default, `cdkDrag` allows free movement in all directions. To restrict dragging to a
specific axis, you can set `cdkDragLockAxis` on `cdkDrag` or `lockAxis` on `<cdk-drop>`
to either `"x"` or `"y"`.

<!-- example(cdk-drag-drop-axis-lock) -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.box {
width: 200px;
height: 200px;
border: solid 1px #ccc;
cursor: move;
display: inline-flex;
justify-content: center;
align-items: center;
background: #fff;
border-radius: 4px;
margin-right: 25px;
transition: box-shadow 200ms cubic-bezier(0, 0, 0.2, 1);
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2),
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12);
}

.box:active {
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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div class="box" cdkDragLockAxis="y" cdkDrag>
I can only be dragged up/down
</div>

<div class="box" cdkDragLockAxis="x" cdkDrag>
I can only be dragged left/right
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Component} from '@angular/core';

/**
* @title Drag&Drop position locking
*/
@Component({
selector: 'cdk-drag-drop-axis-lock-example',
templateUrl: 'cdk-drag-drop-axis-lock-example.html',
styleUrls: ['cdk-drag-drop-axis-lock-example.css'],
})
export class CdkDragDropAxisLockExample {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
.container {
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
}

.list {
border: solid 1px #ccc;
min-height: 60px;
background: white;
border-radius: 4px;
overflow: hidden;
display: block;
}

.box {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
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);
}

.box:last-child {
border: none;
}

.list.cdk-drop-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<div class="container">
<h2>To do</h2>

<cdk-drop #todoList [data]="todo" [connectedTo]="[doneList]" class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let item of todo" cdkDrag>{{item}}</div>
</cdk-drop>
</div>

<div class="container">
<h2>Done</h2>

<cdk-drop #doneList [data]="done" [connectedTo]="[todoList]" class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let item of done" cdkDrag>{{item}}</div>
</cdk-drop>
</div>

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';

/**
* @title Drag&Drop connected sorting
*/
@Component({
selector: 'cdk-drag-drop-connected-sorting-example',
templateUrl: 'cdk-drag-drop-connected-sorting-example.html',
styleUrls: ['cdk-drag-drop-connected-sorting-example.css'],
})
export class CdkDragDropConnectedSortingExample {
todo = [
'Get to work',
'Pick up groceries',
'Go home',
'Fall asleep'
];

done = [
'Get up',
'Brush teeth',
'Take a shower',
'Check e-mail',
'Walk dog'
];

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);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.list {
width: 500px;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: white;
border-radius: 4px;
overflow: hidden;
}

.box {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
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);
}

.box:last-child {
border: none;
}

.list.cdk-drop-dragging .box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<cdk-drop class="list" (dropped)="drop($event)">
<div class="box" *ngFor="let movie of movies" cdkDrag>
{{movie.title}}
<img *cdkDragPreview [src]="movie.poster" [alt]="movie.title">
</div>
</cdk-drop>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';

/**
* @title Drag&Drop custom preview
*/
@Component({
selector: 'cdk-drag-drop-custom-preview-example',
templateUrl: 'cdk-drag-drop-custom-preview-example.html',
styleUrls: ['cdk-drag-drop-custom-preview-example.css'],
})
export class CdkDragDropCustomPreviewExample {
// tslint:disable:max-line-length
movies = [
{
title: 'Episode I - The Phantom Menace',
poster: 'https://upload.wikimedia.org/wikipedia/en/4/40/Star_Wars_Phantom_Menace_poster.jpg'
},
{
title: 'Episode II - Attack of the Clones',
poster: 'https://upload.wikimedia.org/wikipedia/en/3/32/Star_Wars_-_Episode_II_Attack_of_the_Clones_%28movie_poster%29.jpg'
},
{
title: 'Episode III - Revenge of the Sith',
poster: 'https://upload.wikimedia.org/wikipedia/en/9/93/Star_Wars_Episode_III_Revenge_of_the_Sith_poster.jpg'
},
{
title: 'Episode IV - A New Hope',
poster: 'https://upload.wikimedia.org/wikipedia/en/8/87/StarWarsMoviePoster1977.jpg'
},
{
title: 'Episode V - The Empire Strikes Back',
poster: 'https://upload.wikimedia.org/wikipedia/en/3/3c/SW_-_Empire_Strikes_Back.jpg'
},
{
title: 'Episode VI - Return of the Jedi',
poster: 'https://upload.wikimedia.org/wikipedia/en/b/b2/ReturnOfTheJediPoster1983.jpg'
},
{
title: 'Episode VII - The Force Awakens',
poster: 'https://upload.wikimedia.org/wikipedia/en/a/a2/Star_Wars_The_Force_Awakens_Theatrical_Poster.jpg'
},
{
title: 'Episode VIII - The Last Jedi',
poster: 'https://upload.wikimedia.org/wikipedia/en/7/7f/Star_Wars_The_Last_Jedi.jpg'
}
];
// tslint:enable:max-line-length

drop(event: CdkDragDrop<{title: string, poster: string}[]>) {
moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
}
}
Loading