Angular 트리 그리드에서 행 끌기

    Ignite UI for Angular에서 RowDrag는 루트 igx-tree-grid 구성 요소에서 초기화되고 rowDraggable 입력을 통해 구성 가능합니다. 행 끌기를 활성화하면 사용자에게 행 끌기를 시작할 수 있는 행 끌기 핸들이 제공됩니다.

    Angular Tree Grid Row Drag Example

    구성

    igx-tree-grid에 대해 행 드래그를 활성화하려면 그리드의 rowDraggable​ ​true로 설정하기만 하면 됩니다. 이 기능이 활성화되면 행 끌기 핸들이 각 행에 표시됩니다. 이 핸들을 사용하여 행 끌기를 시작할 수 있습니다.

    <igx-tree-grid [rowDraggable]="true">
     ...
    </igx-tree-grid>
    

    드래그 핸들을 클릭하고 버튼을 누른 채 커서를 움직이면 그리드의 rowDragStart 이벤트가 시작됩니다. 언제든지 클릭을 놓으면 rowDragEnd 이벤트가 발생합니다.

    아래에서는 행 드래그를 지원하도록 igx-tree-grid 구성하는 방법과 드롭 이벤트를 적절하게 처리하는 방법에 대한 연습을 찾을 수 있습니다.

    이 예에서는 그리드에서 지정된 영역으로 행을 드래그하는 작업을 처리하고, 이를 놓을 때 그리드에서 제거합니다.

    Drop Areas

    행 드래그를 활성화하는 것은 매우 쉬웠지만 이제 행 삭제를 처리하는 방법을 구성해야 합니다. igxDrop 지시문을 사용하여 행을 삭제할 위치를 정의할 수 있습니다.

    먼저 앱 모듈에서 IgxDragDropModule을 가져와야 합니다.

    import { ..., IgxDragDropModule } from 'igniteui-angular';
    // 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>
    

    다음을 사용하여 놓을 수 없는 영역에 행을 놓을 때 애니메이션을 활성화할 수 있습니다. animation 매개변수 rowDragEnd 이벤트. true로 설정하면 드래그된 행을 놓을 수 없는 영역 위에 놓으면 원래 위치로 다시 애니메이션이 적용됩니다.

    다음과 같이 애니메이션을 활성화할 수 있습니다:

    export class IgxTreeGridRowDragComponent {
    
        public onRowDragEnd(args) {
            args.animation = true;
        }
    
    }
    

    Drop Area Event Handlers

    템플릿에 놓기 영역을 정의한 후에는 해당 항목에 대한 핸들러를 선언해야 합니다. igxDrop '에스 enter, leave 그리고 dropped 우리 컴포넌트의 이벤트.ts 파일.

    먼저, enterleave 핸들러를 살펴보겠습니다. 이러한 방법에서는 드래그의 고스트 아이콘을 변경하여 사용자에게 행을 드롭할 수 있는 영역 위에 있음을 표시할 수 있습니다.

    export class IgxTreeGridRowDragComponent {
        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;
                }
            }
        }
    }
    

    changeGhostIcon 비공개 메소드는 드래그 고스트 내부의 아이콘을 변경합니다. 메서드의 로직은 드래그 표시기 컨테이너에 적용되는 igx-grid__drag-indicator 클래스를 사용하여 아이콘이 포함된 요소를 찾아 요소의 내부 텍스트를 전달된 텍스트로 변경합니다. 아이콘 자체는 material 글꼴 세트에서 가져온 것이며 별도의 enum에 정의됩니다.

    enum DragIcon {
        DEFAULT = 'drag_indicator',
        ALLOW = 'remove'
    }
    

    다음으로 사용자가 실제로 놓기 영역 내부에 행을 놓을 때 어떤 일이 발생해야 하는지 정의해야 합니다.

    export class IgxTreeGridRowDragComponent {
    
        public onDropAllowed(args: IDropDroppedEventArgs) {
            const draggedRow: RowType = args.dragData;
            draggedRow.delete();
        }
    
    }
    

    행이 삭제되면 해당 행의 delete() 메서드를 호출하기만 하면 됩니다.

    Note

    이벤트 인수(args.dragData.data) 또는 다른 행 속성의 행 데이터를 사용하는 경우 전체 행이 인수에 참조로 전달됩니다. 즉, 원하는 경우 필요한 데이터를 복제해야 합니다. 이를 소스 그리드의 것과 구별합니다.

    Templating the drag ghost

    드래그 고스트는 igx-tree-grid 본문 내부의 <ng-template>에 적용되는 IgxRowDragGhost 지시문을 사용하여 템플릿화할 수 있습니다.

    <igx-tree-grid>
    ...
       <ng-template igxRowDragGhost>
            <div>
                <igx-icon fontSet="material">arrow_right_alt</igx-icon>
            </div>
        </ng-template>
    ...
    </igx-tree-grid>
    

    구성 결과는 행 드래그 및 다중 선택이 활성화된 igx-tree-grid에서 아래에 표시될 수 있습니다. 데모에서는 현재 드래그된 행의 개수를 보여줍니다.

    예제 데모

    Templating the drag icon

    드래그 핸들 아이콘은 그리드의 dragIndicatorIconTemplate 사용하여 템플릿화할 수 있습니다. 우리가 만들고 있는 예제에서 아이콘을 기본 아이콘(drag_indicator)에서 drag_handle로 변경해 보겠습니다. 이를 위해 igxDragIndicatorIcon 사용하여 igx-tree-grid 본문 내부에 템플릿을 전달할 수 있습니다.

    <igx-tree-grid>
    ...
        <ng-template igxDragIndicatorIcon>
            <igx-icon>drag_handle</igx-icon>
        </ng-template>
    ...
    </igx-tree-grid>
    

    새 아이콘 템플릿을 설정한 후에는 DragIcon enumDEFAULT 아이콘도 조정해야 합니다. 그러면 changeIcon 메서드에 의해 적절하게 변경됩니다.

    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

    그리드의 행 드래그 이벤트와 igxDrop 지시문을 사용하면 행을 드래그하여 재정렬할 수 있는 그리드를 생성할 수 있습니다.

    모든 작업은 그리드 본체 내부에서 발생하므로 여기에 igxDrop 지시문을 첨부해야 합니다.

    <igx-tree-grid igxPreventDocumentScroll  #treeGrid [data]="localData" [rowDraggable]="true" foreignKey="ParentID"
        [primaryKey]="'ID'" (rowDragStart)="rowDragStart($event)" igxDrop (dropped)="dropInGrid($event)">
        ...
    </igx-tree-grid>
    
    Note

    그리드에 대해 primaryKey 지정되어 있는지 확인하세요! 논리에는 행을 올바르게 다시 정렬할 수 있도록 행에 대한 고유 식별자가 필요합니다.

    rowDraggable 활성화되고 드롭 영역이 정의되면 드롭 이벤트에 대한 간단한 핸들러를 구현해야 합니다. 행을 드래그할 때 다음을 확인하세요.

    • 행이 확장되었나요? 그렇다면 접으세요.
    • 행이 그리드 내부에 삭제되었습니까?
    • 그렇다면 드래그된 행이 다른 어느 행에 삭제되었습니까?
    • 대상 행을 찾았으면 data 배열에서 레코드 위치를 바꿉니다.
    • 행이 처음에 선택되었습니까? 그렇다면 선택됨으로 표시하세요.

    아래에서는 구성 요소의.ts 파일에 구현된 내용을 볼 수 있습니다.

    export class TreeGridRowReorderComponent {
        public rowDragStart(args: any): void {
            const targetRow = args.dragData;
            if (targetRow.expanded) {
                this.treeGrid.collapseRow(targetrow.key);
            }
        }
    
        public dropInGrid(args: IDropDroppedEventArgs): void {
            const draggedRow = args.dragData;
            const event = args.originalEvent;
            const cursorPosition: Point = { x: event.clientX, y: event.clientY };
            this.moveRow(draggedRow, cursorPosition);
        }
    
        private moveRow(draggedRow: RowType, cursorPosition: Point): void {
            const row = this.catchCursorPosOnElem(this.treeGrid.rowList.toArray(), cursorPosition);
            if (!row) { return; }
            if (row.data.ParentID === -1) {
                this.performDrop(draggedRow, row).ParentID = -1;
            } else {
                if (row.data.ParentID === draggedrow.data.ParentID) {
                    this.performDrop(draggedRow, row);
                } else {
                    const rowIndex = this.getRowIndex(draggedrow.data);
                    this.localData[rowIndex].ParentID = row.data.ParentID;
                }
            }
            if (draggedRow.selected) {
                this.treeGrid.selectRows([this.treeGrid.rowList.toArray()
                    .find((r) => r.rowID === draggedrow.key).rowID], false);
            }
    
            this.localData = [...this.localData];
        }
    
        private performDrop(
            draggedRow: IgxTreeGridRowComponent, targetRow: IgxTreeGridRowComponent) {
            const draggedRowIndex = this.getRowIndex(draggedrow.data);
            const targetRowIndex: number = this.getRowIndex(targetrow.data);
            if (draggedRowIndex === -1 || targetRowIndex === -1) { return; }
            this.localData.splice(draggedRowIndex, 1);
            this.localData.splice(targetRowIndex, 0, draggedrow.data);
            return this.localData[targetRowIndex];
        }
    
        private getRowIndex(rowData: any): number {
            return this.localData.indexOf(rowData);
        }
    
        private catchCursorPosOnElem(rowListArr: IgxTreeGridRowComponent[], cursorPosition: Point)
            : IgxTreeGridRowComponent {
            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;
                }
            }
    
            return null;
        }
    }
    

    이러한 몇 가지 간단한 단계를 통해 드래그/드롭을 통해 행을 재정렬할 수 있는 그리드를 구성했습니다! 다음 데모에서 위 코드가 실제로 작동하는 모습을 볼 수 있습니다.

    또한 행 선택이 활성화되어 있으며 드래그된 행을 삭제할 때 선택이 유지됩니다.

    Limitations

    현재 rowDraggable 지시어에 대해 알려진 제한 사항은 없습니다.

    API References

    Additional Resources

    우리 커뮤니티는 활동적이며 항상 새로운 아이디어를 환영합니다.