6

I need to access the model by the html element in angular2. In my case I use ng2-dragula to perform drag and drop and its service only has access to the html elements that are dragged. And I need to update the corresponding model of the element. Heres the issue at github.

Yaroslav Yakovlev
  • 5,652
  • 5
  • 35
  • 57
  • 1
    By "model of the element" do you mean some component's properties? Some code would help (Plunker preferred). – Mark Rajcok Apr 15 '16 at 15:30
  • @MarkRajcok The code is at github, the link is in the end of the question. I meant angular2 model that makes this element appear. Let me know if its not clear after checking the code. – Yaroslav Yakovlev Apr 16 '16 at 20:37
  • I'm not aware of any way to go "from HTML element to component" -- i.e., given an HTML, I don't know how to get a reference to the component where that HTML element is used... the component whose template has that HTML element. – Mark Rajcok Apr 18 '16 at 14:26
  • Seems there should be a dirty way of using the ng.probe(htmlElement), but its used for debug purposes only. So for now its like "it can be done", didnt check how ng.probe works under the hood. – Yaroslav Yakovlev Dec 29 '16 at 10:59

3 Answers3

2

You can get the model of your item by searching for the index of the element in the elementList provided by the arguments of the subscription.

dragulaService.drop.subscribe(e => this.onDrop(e.slice(1)));

See?

UPDATE: Simplification (Thanks to Dracco)

private onDrop(args) {

    let [e, el] = args; //element, elementList
    let i = el.children.indexOf(e),
    item = i+1? this.items[i] : null;

    console.log(item); //The item
}

this.items is the variable where you store the list you pass to dragula. (e.g: [dragulaModel]="items").

I wish there was a simpler way. Tell me if you find one!

Old way:

private onDrop(args) {

    let [e, el] = args; //element, elementList
    let item;
    for(let i in el.children){
        if(el.children[i]==e){
            item = this.items[+i];
            break;                
        }
    }

    console.log(item); //The item
}

EDIT: the simplification had an error.

Umagon
  • 483
  • 4
  • 15
0

If your ngFor is compiled from an array, you need to provide model by setting the dragulaModel attribute on the bag element.

<ul [dragula]='"bag-one"' [dragulaModel]='items'> <li *ngFor="let item of items"></li> </ul>

And whenever you re-position the items, the model will be synced. In your component, you can easily get the updated model by doing this.

this.dragulaService.drop.subscribe((value) => {
        //let [bagName, e, el] = value;
        console.log(this.items);
    });

You will notice that the items are re-positioned in your model.

Abin
  • 1,409
  • 1
  • 12
  • 16
0

Make sure to wrap el.children in a ES6 Array.

let i = el.children.indexOf(e)

Should be

let i = Array.from(el.children).indexOf(e)

I also found that retrieving the child element with the index from the parent list produced unpredictable results and sometimes generated new undefined items.

Alternative Direct ID Solution:

<ion-item *ngFor="let child of children" [id]="child"></ion-item>

and then in the onDrop method

console.log(e.id);