buttonwoodcx / bcx-aurelia-reorderable-repeat

An Aurelia repeater supports drag & drop reordering automatically.
https://buttonwoodcx.github.io/doc-bcx-aurelia-dnd/reorderable-repeat
MIT License
19 stars 5 forks source link

Re-ordering across nested lists #6

Closed ben-girardet closed 5 years ago

ben-girardet commented 5 years ago

I've tried to use the reorderable-repeat attribute with reorderable-group="group" to reorder items across nested lists (items arranged in a tree fashion) but it doesn't work. When trying to move an item from a nested list, it only support dropping it in the main (first level) list and not in any child lists.

Here is my code:

<!-- view test.html-->
<template>
  <require from="./test.css"></require>
  <div class="list">
    <div class="item" reorderable-group="group" reorderable-repeat.for="item of items || []">
      ${item.name}
      <div class="list">
        <div class="item" reorderable-group="group" reorderable-repeat.for="childItem of item.children || []">
          ${childItem.name}
        </div>
      </div>
    </div>
  </div>
</template>
/* CSS test.css */
.list {
  padding: 10px;
}

.item {
  padding: 10px;
  border: 1px solid #ccc;
  margin-bottom: 5px;
}
// view-model test.ts
interface Item {
  name: string;
  children?: Array<Item>;
}

export class Test {

  items: Array<Item>;

  constructor() {
    this.items = [
      {
        name: 'Item 1',
        children: [
          {
            name: 'Item 1.1',
          },
          {
            name: 'Item 1.2'
          }
        ]
      },
      {
        name: 'Item 2',
        children: [
          {
            name: 'Item 2.1',
          },
          {
            name: 'Item 2.2'
          }
        ]
      }
    ]
  }

}

Screenshot of original list positions:

capture d ecran 2018-10-08 a 10 55 40

Nested items can only be dropped in first-level list as such:

capture d ecran 2018-10-08 a 10 56 09

You might also notice that the original item has not left its original list after the drop.

3cp commented 5 years ago

In short, reorderable-repeat is not smart enough to handle your use case.

There are few issues.

  1. you cannot use || [] in binding, reorderable-repeat needs to directly handle the model array, not the array created by aurelia out of expression items || []. reorderable-repeat is NOT working on the array your intended.

  2. reorderable-repeat doesn't know how to add placeholder {children:[]} to the item, when you move a 2nd level item to 1st level. You know this, that's why you tried to use item.children || [].

  3. you have not thought through the scenario, for example, what about I move item1 to between item2.1 and item2.2, are you going to bring item1.1 and item1.2 together and create 3 level hierarchy? If this is what you want, you view template does not yet support more than 2 level. Furthermore, once opened this scenario, you essentially open the gate to allow infinite nesting. I can create 3 level by drag-and-drop, then create 4 level too, then 5 level, as long as I have enough items to stack together.

For tricky use case like this, I think you need to go down to bcx-aurelia-dnd. It's not going to be very easy. What I can think about is to disallow some drag-and-drop, for example, because item1 has child items, we don't allow it to be dropped to 2nd level, only an empty 1st level item can be moved to 2nd level. For creating placeholder {children:[]}, you can do in dndDrop() callback when you mutate the array.

Hope this helps.

3cp commented 5 years ago

You can try removing || [], and add empty children: [] to all 2nd level items. But even if it works, it's only half-working, because once you try 3), it's all broken.

ben-girardet commented 5 years ago

Thank you for taking the time to answer this issue. You're right about your scenario, I kept it simple but then introduced some edge cases. My end goal is to manage infinite nested lists. I did this some time ago using the dragula library. As you said, it includes some tricky drag and drop use cases, especially because I also need to be able to create new items anywhere in the tree.

I recently discovered bcx-aurelia-reorderable-repeat and I have to say I'm very impressed by the work and the simplicity of usage. I was secretly hoping that it could simplify my tree drag and drop system but it seems that it's going to require the same job than with dragula. I'll probably give it a try in a near future with bcx-aurelia-dnd.

Back to the original question, it seems to me that the main issue for bcx-aurelia-reorderable-repeat to work in a nested way is the fact that once I drag an item over a nested list, it' ALSO over the parent list. Therefore it's hard to determine easily which one is the "droppable" list. Could be achieved by looking at the deepest list in the DOM. But not sure it's doable so easily...

Anyway... just wanted to acknowledge your answer and give a little more thoughts. I think we can close this issue if it's not something that is fixable anytime soon.

3cp commented 5 years ago

Thx for the compliments.

The repeat group is designed to be very simple. That’s why I suggest you to go down to bcx-aurelia-dnd, where you can do fine controll.

It might be easier than using dragula, because our dnd allows you to work on model layer, instead of DOM layer. But it will take some exercise to feel comfortable with our dnd design. The examples in doc site can help you understand our approach.

3cp commented 5 years ago

BTW, you can use recursion in aurelia view template.

item-view.html

<template>
  <p>${item.name}</p>
  <div if.bind="item.children.length">
    <item-view repeat.for="c of item.children" item.bind="c"></item-view>
  </div>
</template>