Dragula如何确定排序顺序 - 如何禁用

8

我正在使用Dragula实现拖放功能。它可以正常工作,但是当我从服务器端刷新列表时就会出问题:

this.columnList = newValue;

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

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));
    }    
}

如果您运行上述代码,您会发现模型与列表同步,如 Items的显示状态 按钮所示。但是,如果我们从 app.component.html 中删除 [dragulaModel]="items",我们将发现模型不再同步。这并不是 dragula 做了什么额外的事情,实际上它做了更少的事情。
现在来解决这个问题...
当同步本地状态时,我们可以尝试以下几种方式:
首先需要注意的是,虽然添加[dragulaModel]="items"可以将列表与数组同步,但我们仍需要一个钩子来执行自定义服务器同步代码,稍后再详细说明。
如果我们忽略dragula框架,也许可以尝试为items创建getter和setter。但是,如果我们将所有items实例重命名为_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;
}

然而上述方法无法生效,或者说它可能有效,但是查看控制台日志后可以发现setter只调用一次,之后所有后续访问都使用getter,并且在拖动期间getter会被多次调用,如果用户悬停并移动,可能会生成数百个调用。此外,让用户知道页面是否需要保存可能会更好,在可能无界限的列表上进行数组比较,不确定数量的次数听起来并不是一个好主意,虽然可能会有纯Java / TypeScript解决方案可以解决这个问题,dragula提供了一种方式,在放置项时仅检查一次。

添加以下代码,替换构造函数,并删除那个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
}

而且你应该会得到一个很好的工作解决方案。


感谢您的积极响应。我实际上正在使用 Dragula 和 Aurelia。看起来您是正确的,但我现在怀疑 Aurelia 尝试重建从服务器端刷新的项目顺序。 - Radenko Zec
不了解Aurelia,但听起来需要另一层抽象。将您的列表复制到另一个列表中,Dragula将使用该列表,当Aurelia决定更新它的列表时,必须有一个钩子可以调用并决定如何协调dragula的顺序与服务器的新列表(可能有其他用户添加的新元素,它们如何被纳入考虑?)。此外,dragula具有根据键更新记录的功能,我还没有调查过,抱歉,但这可能值得一看。 - Quaternion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接