8

我正在使用 Dragula 进行拖放功能。它一直有效,直到我从服务器端刷新我的列表:

this.columnList = newValue;

看起来 Dragula 想要像以前一样保留列表中的顺序,所以它弄乱了服务器端的排序顺序。我不需要这个功能。我已阅读文档、教程、示例,但找不到如何在 Dragula 中禁用自动排序。

4

1 回答 1

6

我很有信心至少在默认情况下没有自动排序。最小的独立示例是我们的朋友。好吧,不管网络是否可以使用更多示例,虽然很难证明是否定的,但我会证明在默认情况下没有自动排序,并尝试猜测问题出在哪里。

抱歉,我才意识到您使用的是纯 JS,并且可能使用的是 AngularJS 而不是 Angular2。无论如何,以下内容应该仍然有些用处。

首先我们需要一个简单的代码库,让我们使用 Angular-CLI 创建代码库(https://www.npmjs.com/package/angular-cli):然后按照如何使用 ng2-dragula 设置 angular-quickstart,我们将具有完全相同的起始基础。

现在将app.component.html的内容替换为:

<div><button (click)="inOrderGreekAlphabet()">In Order Greek Alphabet</button></div>
<div><button (click)="reversedGreekAlphabet()">Reversed Greek Alphabet</button></div>
<div><button (click)="displyStateOfItems()">Display state of Items</button></div>
<div>
    <div class='wrapper'>
        <div class='container' [dragula]='"first-bag"'  [dragulaModel]="items">
            <div *ngFor="let item of items">{{item}}</div>
        </div>
    </div>
</div>

将 app.component.ts 的内容替换为:

import {Component} from '@angular/core';
import {DragulaService} from 'ng2-dragula/ng2-dragula';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    viewProviders: [DragulaService]
})
export class AppComponent {
    public items: string[];
    private GREEK_ALPHABET:string[] = ["alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa", "lambda", "mu", "nu", "xi", "omicron", "pi", "rho", "sigma", "tau", "upsilon", "phi", "chi", "psi", "omega"];

    constructor() {
        this.inOrderGreekAlphabet();
    }

    public inOrderGreekAlphabet(){
        this.items = this.GREEK_ALPHABET.slice();
    }

    public reversedGreekAlphabet() {
        this.items = this.GREEK_ALPHABET.reverse();
    }

    public displyStateOfItems(){
        alert(JSON.stringify(this.items));
    }    
}

如果您运行上面的代码,您会发现模型与列表同步,如“项目的显示状态”按钮所示。但是,如果我们[dragulaModel]="items"app.component.html中删除,我们会发现模型没有同步。并不是说dragula 在做额外的事情,它实际上是在做更少的事情。


现在要解决问题...

在同步本地状态时,我们可以尝试以下几种方式:

首先请注意,虽然添加[dragulaModel]="items"确实将列表与数组同步,但我们仍然需要一个用于自定义服务器同步代码的钩子,稍后会详细介绍。

如果我们忽略 Dragula 框架并尝试为项目创建一个 getter setter。但是,如果我们将所有项目实例重命名为 _items 然后添加:

//This is to demonstrate an issue, this is NOT A Solution!
get items():string[]{
    console.log("call from getter: could do server sync here?");
    return this._items;
}

set items(i:string[]){
    console.log("call from setter: or perhaps here?");
    this._items = i;
}

但是上面的 WILL NOT WORK,或者更确切地说它可以工作,但查看控制台日志显示 setter 被调用一次,然后所有后续访问都使用 getter 完成,并且在拖动期间调用 getter 多次,如果用户悬停和移动可能会在几秒钟内产生数百个调用。此外,让用户知道是否需要保存页面可能会很好,对潜在的无界列表进行数组比较,不确定的次数听起来不是一个好主意,虽然可能有可以解决此拖拽的纯 Java/TypeScript 解决方案提供了一种在项目被丢弃时只进行一次检查的方法。

添加以下代码,替换构造函数,并删除该 setter/getter,因为这是一个愚蠢的想法(我们真的只对 drop 部分感兴趣,但完整性永远不会受到伤害):

constructor(private dragulaService: DragulaService) {
    dragulaService.drag.subscribe((value) => {
        console.log(`drag: ${value[0]}`);
        this.onDrag(value.slice(1));
    });
    dragulaService.drop.subscribe((value) => {
        console.log(`drop: ${value[0]}`);
        this.onDrop(value.slice(1));
    });
    dragulaService.over.subscribe((value) => {
        console.log(`over: ${value[0]}`);
        this.onOver(value.slice(1));
    });
    dragulaService.out.subscribe((value) => {
        console.log(`out: ${value[0]}`);
        this.onOut(value.slice(1));
    });
    this.inOrderGreekAlphabet();
}

private onDrag(args) {
    let [e, el] = args;
    //do something
}

private onDrop(args) {
    let [e, el] = args;
    // do something
}

private onOver(args) {
    let [e, el, container] = args;
    // do something
}

private onOut(args) {
    let [e, el, container] = args;
    // do something
}

以上内容取自https://github.com/valor-software/ng2-dragula#events并提供了在不使用指令的情况下手动实现同步的能力,dragulaModel但我们也可以在该指令的基础上构建文档显示(https://github.com/valor-software/ng2-dragula#special-events-for-ng2-dragula),所以我们至少需要(并且我们必须使用 dragulaModel在这种情况下指令):

constructor(private dragulaService: DragulaService) {
    dragulaService.dropModel.subscribe((value) => {
        console.log(`dropModel: ${value[0]}`);
        this.onDropModel(value);
    });
    this.inOrderGreekAlphabet();
}

private onDropModel(args){
    let [bagName, el, target, source] = args;
    //do something, such as sync items with the server.
    //or setting a flag to indicate if items is different from when it was last saved
}

你应该有一个很好的工作解决方案。

于 2017-04-27T20:08:36.407 回答