2

Resources I've looked at:

https://github.com/valor-software/ng2-dragula

Issues describing similar problems:

https://github.com/valor-software/ng2-dragula/issues/309

https://github.com/valor-software/ng2-dragula/issues/663

I'm using ng2-dragula and I'm trying to have nested draggable items but I cannot for the life of me figure out how to do it despite looking at examples.

This one allows columns to be dragged from one row to another just fine:

<div>
  <row *ngFor="let row of rows" dragula="columns" [dragulaModel]="row?.columns">
    <column *ngFor="let column of row?.columns"></column>
  </row>
</div>

However I also need the rows themselves to be draggable so I did this:

<div dragula="rows" [dragulaModel]="rows">
  <row *ngFor="let row of rows" dragula="columns" [dragulaModel]="row?.columns">
    <column *ngFor="let column of row?.columns"></column>
  </row>
</div>

This allows the rows to be draggable but now the columns doesn't work, if I try to drag a column into another row I get the error:

ERROR DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

The columns also cannot be re-ordered within the same row.

It appears as if dragging a column causes the row to be dragged instead of the column.

What am I doing wrong here?

2 Answers 2

3

I made an example for you. Let me know if this answers your question. Setting dragula options for the row "bag" allows you to pass your own invalid handler. So, dont let the parent container drag if you are attempting to drag something with the class name "column" for example.

https://embed.plnkr.co/Y4Gy0nHuGKpaYQObXLWG/

In your constructor, or whenever you set your dragula options for the parent dragula:

constructor(dragulaService: DragulaService) {
  dragulaService.setOptions('bag', {
    invalid(el, handle) {
      // If the selected element className is column, 
      //    dont allow the row to be dragged. This will allow 
      //    the column to be dragged separate from the row. 
      return (el.className == "column");
    }
  });
}

HTML:

<div [dragula]="'bag'" [dragulaModel]="rows">
  <div class="row" *ngFor="let row of rows">
    {{row.value}}
    <div [dragula]="'bag2'" [dragulaModel]="row.columns">
      <div class="column" *ngFor="let column of row.columns">
          {{column.value}}
      </div>
    </div>
  </div>
</div>
Sign up to request clarification or add additional context in comments.

2 Comments

Please include the relevant code in your answer, and not in a link which may someday stop functioning. Like today, that link doesn't even give me a demo, it gives me a wall of text explanations and code which you might as well have included here.
Please help. Your solution looks promising, but system.js has an error in your plunkr. Thanks.
2

Try this:

<div dragula="myBag" [dragulaModel]="rows" class="iAmContainer">
  <row *ngFor="let row of rows" dragula="myBag" [dragulaModel]="row?.columns" class="iAmRow">
    <column *ngFor="let column of row?.columns" class="iAmCol"></column>
  </row>
</div>

I set dragula="myBag" to both row and column and set classes on elements.

Now in ngOnInit use code similar to this:

const bag: any = this.dragulaService.find('myBag');
if (bag !== undefined) this.dragulaService.destroy('myBag');
this.dragulaService.setOptions('myBag', {
  revertOnSpill: true,
  accepts: function (el, target, source, sibling) {
    return !el.contains(target) && 
           ((el.className == 'iAmCol' && target.className == 'iAmRow') || 
            (el.className == 'iAmRow' && target.className == 'iAmContainer'));
  },
});

I used the className of the element and target to determine if they are compatible.

1 Comment

Thanks for the answer, it looks like it would work as well but I accepted the other guy's answer due to a working demo. Have a nice day :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.