How to get attribute values from html in angular 4

Anuj K.C. picture Anuj K.C. · Nov 30, 2017 · Viewed 11.8k times · Source

I am working on angular 4 project, I had a requirement to drag item, So I was using ng2-dragula plugin to do it for me. Now I need to extract data-id attribute from each row after drop to specific position.

 dragulaService.drop.subscribe(
      (args) =>{
        const [bagName, elSource, bagTarget, bagSource, elTarget] = args;
        console.log('after', $(bagSource)); // element after the inserted element
});

In $bagSource variable I will get each rows in new order. Say it be

<tr attributes  data-id="23"><tr>
<tr attributes  data-id="2"><tr>
<tr attributes  data-id="32"><tr>

How could I extract data-id from each tr fields. I need to get each id in their new order in an array. My required result should be [23,2,32];

jquery $(element).attr("data-id") equivalent in angular 4.

Answer

Patryk Brejdak picture Patryk Brejdak · Nov 30, 2017

Something similiar to jquery $(element).attr("data-id") can be achieved with @ViewChild and some old-fashioned javascript. It would look like:

Use this only when drag zone and table is not related (if it is use @user3263307 answer it's more Angular-friendly). However the best option would be make use of [attr.data-id]="someVariable", but since I don't know your app structure can't help you with implementing this method.

.*html File

<table #tableRef>
    <tr attributes  [attr.data-id]="23"><tr>
    <tr attributes  [attr.data-id]="2"><tr>
    <tr attributes  [attr.data-id]="32"><tr>
</table>

Simply #tableRef is something like template variable which angular will bind with @ViewChild in component file.

*.component.ts

@ViewChild() tableRef: ElementRef;

    public getIds() {
        if (!this.tableRef|| !this.tableRef.nativeElement)
            return;
        //assuming that table would have only one `tbody` tag.
        let tableBody = this.tableRef.tBodies[0];
        if (!tableBody)
           return;

        // we need to use Array.from, because `.children` returns HTMLCollection<Element>
        // type which is not handy to iterate through it.

        let childs: Array<HTMLTableSectionElement> = Array.from(tableBody.nativeElement.children);
        let arrIds = [];
        for(let child of childs) {
            if (!(child.nodeName && child.nodeName.toLowerCase() == "tr"))
                continue;

            arrIds.push(child.dataset.id);
        }
    }

Please note that it's a bit brutal method for angular since it's best not to interfere into HTML DOM structure. However as long we are only getting data from elements everything should be fine.

Please note that too about using @ViewChild.

Use this API as the last resort when direct access to DOM is needed. Use templating and data-binding provided by Angular instead. Alternatively you can take a look at Renderer2 which provides API that can safely be used even when direct access to native elements is not supported. Relying on direct DOM access creates tight coupling between your application and rendering layers which will make it impossible to separate the two and deploy your application into a web worker.

From Angular docs link