Angular 계층형 그리드에서 행 끌기
In Ignite UI for Angular Hierarchical Grid, RowDrag is initialized on the root igx-hierarchical-grid component and is configurable via the rowDraggable input. Enabling row dragging provides users with a row drag-handle with which they can initiate dragging of a row.
Angular Hierarchical Grid Row Drag Example
구성
In order to enable row-dragging for your igx-hierarchical-grid, all you need to do is set the grid's rowDraggable to true. Once this is enabled, a row-drag handle will be displayed on each row. This handle can be used to initiate row dragging.
<igx-hierarchical-grid [rowDraggable]="true">
...
</igx-hierarchical-grid>
Clicking on the drag-handle and moving the cursor while holding down the button will cause the grid's rowDragStart event to fire. Releasing the click at any time will cause rowDragEnd event to fire.
Below, you can find a walkthrough on how to configure an igx-hierarchical-grid to support row dragging and how to properly handle the drop event.
이 예에서는 그리드에서 지정된 영역으로 행을 드래그하는 작업을 처리하고, 이를 놓을 때 그리드에서 제거합니다.
Drop Areas
Enabling row-dragging was pretty easy, but now we have to configure how we'll handle row-dropping.
We can define where we want our rows to be dropped using the igxDrop directive.
First we need to import the IgxDragDropModule in our app module:
import { ..., IgxDragDropModule } from 'igniteui-angular/directives';
// import { ..., IgxDragDropModule } from '@infragistics/igniteui-angular'; for licensed package
...
@NgModule({
imports: [..., IgxDragDropModule]
})
그런 다음 템플릿에서 지시어 선택기를 사용하여 드롭 영역을 정의합니다.
<div class="drop-area" igxDrop (enter)="onEnterAllowed($event)" (leave)="onLeaveAllowed($event)"
(dropped)="onDropAllowed($event)">
<igx-icon>delete</igx-icon>
<div>Drag a row here to delete it</div>
</div>
You may enable animation when a row is dropped on a non-droppable area using the animation parameter of the rowDragEnd event. If set to true, the dragged row will animate back to its' original position when dropped over a non-droppable area.
다음과 같이 애니메이션을 활성화할 수 있습니다:
export class IgxHierarchicalGridRowDragComponent {
public onRowDragEnd(args) {
args.animation = true;
}
}
Drop Area Event Handlers
Once we've defined our drop-area in the template, we have to declare our handlers for the igxDrop's enter, leave and dropped events in our component's .ts file.
First, let's take a look at our enter and leave handlers. In those methods, we just want to change the icon of the drag's ghost so we can indicate to the user that they are above an area that allows them to drop the row:
export class IgxHierarchicalGridRowDragComponent {
public onEnterAllowed(args) {
this.changeGhostIcon(args.drag.ghostElement, DragIcon.ALLOW);
}
public onLeaveAllowed(args) {
this.changeGhostIcon(args.drag.ghostElement, DragIcon.DEFAULT);
}
private changeGhostIcon(ghost, icon: string) {
if (ghost) {
const currentIcon = ghost.querySelector('.igx-grid__drag-indicator > igx-icon');
if (currentIcon) {
currentIcon.innerText = icon;
}
}
}
}
The changeGhostIcon private method just changes the icon inside of the drag ghost. The logic in the method finds the element that contains the icon (using the igx-grid__drag-indicator class that is applied to the drag-indicator container), changing the element's inner text to the passed one.
The icons themselves are from the material font set and are defined in a separate enum:
enum DragIcon {
DEFAULT = 'drag_indicator',
ALLOW = 'remove'
}
다음으로 사용자가 실제로 놓기 영역 내부에 행을 놓을 때 어떤 일이 발생해야 하는지 정의해야 합니다.
export class IgxHierarchicalGridRowDragComponent {
public onDropAllowed(args: IDropDroppedEventArgs) {
const draggedRow: RowType = args.dragData;
draggedRow.delete();
}
}
Once the row is dropped, we just call the row's delete() method
Note
When using row data from the event arguments (args.dragData.data) or any other row property, note that the entire row is passed in the arguments as a reference, which means that you must clone the data you need, if you want to distinguish it from the one in the source grid.
Templating the drag ghost
The drag ghost can be templated using the IgxRowDragGhost directive, applied to a <ng-template> inside of the igx-hierarchical-grid's body:
<igx-hierarchical-grid>
...
<ng-template igxRowDragGhost>
<div>
<igx-icon fontSet="material">arrow_right_alt</igx-icon>
</div>
</ng-template>
...
</igx-hierarchical-grid>
The result of the configuration can be seem below in a igx-hierarchical-grid with row dragging and multiple selection enabled. The demo shows the count of the currently dragged rows:
예제 데모
드래그 고스트는 모든 그리드 수준에서 템플릿화할 수 있으므로 여러 고스트 템플릿을 가지거나 단일 행 아일랜드에 대한 템플릿만 제공할 수 있습니다.
<igx-hierarchical-grid>
...
<ng-template igxRowDragGhost>
<div>
<igx-icon fontSet="material">arrow_right_alt</igx-icon>
</div>
</ng-template>
<igx-row-island>
...
<ng-template IgxRowDragGhost>
<img src="smile.gif" height="42" width="42">
</ng-template>
</igx-row-island>
...
</igx-hierarchical-grid>
Templating the drag icon
The drag handle icon can be templated using the grid's dragIndicatorIconTemplate. In the example we're building, let's change the icon from the default one (drag_indicator) to drag_handle.
To do so, we can use the igxDragIndicatorIcon to pass a template inside of the igx-hierarchical-grid's body:
<igx-hierarchical-grid>
...
<ng-template igxDragIndicatorIcon>
<igx-icon>drag_handle</igx-icon>
</ng-template>
...
</igx-hierarchical-grid>
Once we've set the new icon template, we also need to adjust the DEFAULT icon in our DragIcon enum, so it's properly change by the changeIcon method:
enum DragIcon {
DEFAULT = "drag_handle",
...
}
Styling the drop area
드롭 핸들러가 올바르게 구성되면 남은 것은 드롭 영역의 스타일을 약간 지정하는 것입니다.
.drop-area {
width: 160px;
height: 160px;
background-color: #d3d3d3;
border: 1px dashed #131313;
display: flex;
justify-content: center;
align-items: center;
flex-flow: column;
text-align: center;
margin: 8px;
}
:host {
display: flex;
justify-content: center;
align-items: center;
flex-flow: column;
width: 100%;
}
결과는 아래 데모에서 확인할 수 있습니다.
예제 데모
Application Demo
Row Reordering Demo
With the help of the grid's row drag events and the igxDrop directive, you can create a grid that allows you to reorder rows by dragging them.
Since all of the actions will be happening inside of the grid's body, that's where you have to attach the igxDrop directive:
<igx-hierarchical-grid #grid [data]="localData" [primaryKey]="'id'"
[rowDraggable]="true" (rowDragStart)="rowDragStart($event)" igxDrop (dropped)="rowDrop($event)">
...
</igx-hierarchical-grid>
Note
Make sure that there is a primaryKey specified for the grid! The logic needs an unique identifier for the rows so they can be properly reordered
Once rowDraggable is enabled and a drop zone has been defined, you need to implement a simple handler for the drop event. When a row is dragged, check the following:
- 행이 확장되었나요? 그렇다면 접으세요.
- 행이 그리드 내부에 삭제되었습니까?
- 그렇다면 드래그된 행이 다른 어느 행에 삭제되었습니까?
- Once you've found the target row, swap the records' places in the
dataarray - 행이 처음에 선택되었습니까? 그렇다면 선택됨으로 표시하세요.
Below, you can see this implemented in the component's .ts file:
export class HGridRowReorderComponent {
public rowDragStart(args: any): void {
const targetRow = args.dragData;
if (targetRow.expanded) {
targetRow.expanded = false;
}
}
public rowDrop(args: IDropDroppedEventArgs): void {
const targetRow = args.dragData;
const event = args.originalEvent;
const cursorPosition: Point = { x: event.clientX, y: event.clientY };
this.moveRow(targetRow, cursorPosition);
}
private moveRow(draggedRow: RowType, cursorPosition: Point): void {
// const parent: IgxHierarchicalGridComponent = (draggedRow as any).grid;
// const parent = args.drag.ghostContext.grid;
const parent = this.hGrid;
const rowIndex: number = this.getTargetRowIndex(parent.rowList.toArray(), cursorPosition);
if (rowIndex === -1) { return; }
const wasSelected = draggedRow.selected;
draggedRow.delete();
parent.data.splice(rowIndex, 0, draggedRow.data);
if (wasSelected) {
parent.selectRows([parent.rowList.toArray()
.find((r) => r.rowID === draggedRow.key).rowID], false);
}
}
private getTargetRowIndex(rowListArr: RowType[], cursorPosition: Point): number {
const targetElem: IgxHierarchicalRowComponent = this.catchCursorPosOnElem(rowListArr, cursorPosition);
return rowListArr.indexOf(rowListArr.find((r) => r.rowData.id === targetElem.rowData.id));
}
private catchCursorPosOnElem(rowListArr: any[], cursorPosition: Point)
: IgxHierarchicalRowComponent {
for (const row of rowListArr) {
const rowRect = row.nativeElement.getBoundingClientRect();
if (cursorPosition.y > rowRect.top + window.scrollY && cursorPosition.y < rowRect.bottom + window.scrollY &&
cursorPosition.x > rowRect.left + window.scrollX && cursorPosition.x < rowRect.right + window.scrollX) {
return row;
} else if (row === rowListArr[rowListArr.length - 1] && cursorPosition.y > rowRect.bottom) {
return row;
}
}
}
}
이러한 몇 가지 간단한 단계를 통해 드래그/드롭을 통해 행을 재정렬할 수 있는 그리드를 구성했습니다! 다음 데모에서 위 코드가 실제로 작동하는 모습을 볼 수 있습니다.
또한 행 선택이 활성화되어 있으며 드래그된 행을 삭제할 때 선택이 유지됩니다.
Limitations
Currently, there are no known limitations for the rowDraggable directive.