buttonwoodcx / bcx-aurelia-dnd

Aurelia Drag and Drop.
https://buttonwoodcx.github.io/doc-bcx-aurelia-dnd
MIT License
21 stars 2 forks source link

reorderable-after-reordering: How to find out which item got moved #7

Closed davidtimovski closed 5 years ago

davidtimovski commented 5 years ago

This isn't as much of an issue as it is a help request. Most sorting libraries give you access to the moved element/item, its previous index, and its new index in the callback that's invoked when the reordering ends. With reorderable-after-reordering I only get the newly reordered list so it's kind of difficult to find out which item was moved and to which new index.

Is there an easy way I can achieve this or will I have to hack some function that compares the previous and new order of the list?

3cp commented 5 years ago

About few months ago I removed some part of the doc that covers your usage. Maybe I need to add them back, or enhance the callback.

Inspect the changes from collection observer, it got what you want.


With Aurelia, you actually don't need this callback. The generic solution is to use Aurelia BindingEngine's collectionObserver. Here is some sample code on how to do that.

import {inject, BindingEngine} from 'aurelia-framework';
@inject(BindingEngine)
export class YourComponent {
  items = [ /* ... */ ];

  constructor(bindingEngine) {
    this.bindingEngine = bindingEngine;
  }

  attached() {
    this._subscriber = this.bindingEngine.collectionObserver(this.items).subscribe((changes) => {
      // `this.items` here is the updated array.
      // `changes` is the aurelia collection mutation, if you know what to inspect it.
    });
  }

  detached() {
    this._subscriber.dispose();
  }
}

This solution catches all mutation on items array, no matter whether the change is triggered by reorderable-repeat.

For only listening to changes triggered by reorderable-repeat, use "reorderable-after-reordering" callback.

3cp commented 5 years ago

The collection observer is definitely not intuitive. I will enhance the callback to add 2nd argument, I just need to think through the shape of object, because in multi-list reordering, fromIndex and toIndex can be on two different arrays.

If you have any suggestion on the shape, let me know. Thanks!

davidtimovski commented 5 years ago

So I'm currently working on that, but for a single list. It's tricky to get the information out properly. What I have now is very convoluted and fragile but works:

async reorder(changes: ICollectionObserverSplice[]) {
  // Added this condition because the method is invoked 
  // whenever I add/remove items from the list as well
  if (changes.length === 2) {
    let oldOrder: number;
    let newOrder: number;
    let movedItem;

    if (changes[0].removed.length > 0) {
      // We end up here when moving from top (0) toward bottom (> 0)
      oldOrder = changes[0].index + 1;
      newOrder = changes[1].index + 1;
      movedItem = changes[0].removed[0];
    } else {
      // We end up here when moving from bottom (> 0) toward top (0)
      oldOrder = changes[1].index;
      newOrder = changes[0].index + 1;
      movedItem = changes[1].removed[0];
    }

    // ...
  }
}

There are +1s in some places because I store my order starting from 1 instead of 0.

3cp commented 5 years ago

I see. I will probably just add 2nd argument to the callback for single list use case only. If I leave the multi-list use case out, it's simple to implement.

3cp commented 5 years ago

use bcx-aurelia-reorderable-repeat v1.1.0, there is 2nd argument in shape {fromIndex, toIndex} for single list mode.

Note only reorderable-after-reordering="methodName" gets the 2 arguments passed in. Not the reorderable-after-reordering.call="method(...)", where arguments were provided by you explicitly.

davidtimovski commented 5 years ago

Wow that's great man. Feature development on call! Works perfectly, thank you!