Kendo Angular 行重新排序的网格 - Angular 4/5 - HTML5 拖放 API

Kendo Grid for Angular Row Reordering - Angular 4/5 - HTML5 Drag and Drop API

我正在尝试实现一个 Kendo-Grid,它具有所宣传的行重新排序功能 here

当 Grid 处理通过 Ajax 调用获取的数据时,行的重新排序(即拖放行)在视图更改之前不起作用(例如:直到用户点击本例中分页中的第 2 页)

下面是我的app.component.ts文件

import { State, process } from '@progress/kendo-data-query';
import { Component, Renderer2, NgZone, AfterViewInit, OnInit, EventEmitter, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import { Subscription } from 'rxjs/Subscription';
import { HttpClient, HttpParams} from '@angular/common/http';

@Component({
    selector: 'my-app',
    template: `
        <kendo-grid
            [data]="gridData"
            [height]="410"
            [pageable]="true"
            [skip]="state.skip"
            [pageSize]="state.take"
            (dataStateChange)="dataStateChange($event)">
            <kendo-grid-column field="id" title="ID" width="60">
            </kendo-grid-column>
            <kendo-grid-column field="title" title="To Do">
            </kendo-grid-column>
            <kendo-grid-column field="completed" title="Completed" width="60">
                <ng-template kendoGridCellTemplate let-dataItem>
                    <input type="checkbox" [checked]="dataItem.completed" disabled/>
                </ng-template>
            </kendo-grid-column>
        </kendo-grid>
    `
})
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
    userData: any[] = []
    public state: State = {
        skip: 0,
        take: 10
    };
    public gridData: any = process(this.userData, this.state);
    private currentSubscription: Subscription;

    constructor(private renderer: Renderer2, private zone: NgZone, private _http: HttpClient) {}

    ngOnInit() {
      this.getUserData();  
    }

    public ngAfterViewInit(): void {
        this.currentSubscription = this.handleDragAndDrop();
    }

    public ngOnDestroy(): void {
        this.currentSubscription.unsubscribe();
    }

    public dataStateChange(state: State): void {
        this.state = state;
        this.gridData = process(this.userData, this.state);
        this.currentSubscription.unsubscribe();
        this.zone.onStable
            .take(1)
            .subscribe(() => this.currentSubscription = this.handleDragAndDrop());
    }

    private handleDragAndDrop(): Subscription {
        const sub = new Subscription(() => {});
        let draggedItemIndex;

        document.querySelectorAll('.k-grid-content tr')
        .forEach(item => {
            this.renderer.setAttribute(item, 'draggable', true);
            const dragStart = Observable.fromEvent(item, 'dragstart');
            const dragOver = Observable.fromEvent(item, 'dragover');
            const drop = Observable.fromEvent(item, 'drop');

            sub.add(dragStart.subscribe(({target}) => {
                draggedItemIndex = target.rowIndex;
            }));

            sub.add(dragOver.subscribe((e: any) => e.preventDefault()));

            sub.add(drop.subscribe((e: any) => {
                e.preventDefault();
                const dataItem = this.gridData.data.splice(draggedItemIndex, 1)[0];
                const dropIndex = e.target.closest('tr').rowIndex;
                this.zone.run(() =>
                    this.gridData.data.splice(dropIndex, 0, dataItem)
                );
            }));
        });

        return sub;
    }

  getUserData() {
    return this._http.get('https://jsonplaceholder.typicode.com/todos')
    .subscribe((fetchedData) => {
      this.userData = fetchedData;
      console.log(this.userData);
      this.gridData = process(this.userData, this.state);
      this.currentSubscription.unsubscribe();
      this.currentSubscription = this.handleDragAndDrop();
    });
  }
}

下面是 app.module.ts 文件

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule } from '@angular/forms';
import { GridModule } from '@progress/kendo-angular-grid';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, GridModule, FormsModule, HttpClientModule],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ]
})

export class AppModule { }

Plunker Here.

注意:我曾尝试在我的 Ajax 数据调用中重新订阅 handleDragAndDropevent,但这也没有用。

提前致谢!

关键是只有在通过 AppComponent.dataStateChange() 调用更改 state 时才调用 AppComponent.handleDragAndDrop()。它发生在网格页面更改时,不会发生在数据初始化时。所以,一个快速的解决办法是

getUserData() {
    return this._http.get('https://jsonplaceholder.typicode.com/todos')
    .subscribe((fetchedData) => {
      this.userData = fetchedData;
      console.log(this.userData);
      this.dataStateChange(this.state); // force state change, encapsulate process() call
    });
  }

固定的 Plunker 是 here