Search code examples
angularrenderer

Angular 8 - How to query DOM elements by their attributes?


I have a dynamically generated an HTML 5 table using the renderer2:

const td = this.renderer.createElement('td');
this.renderer.setProperty(td, 'id', letter + i);
this.renderer.setAttribute(td, 'contenteditable', 'true');
this.renderer.setAttribute(td, 'r', i + '');
this.renderer.setAttribute(td, 'c', j + '');

The table has the following structure

<table _ngcontent-iji-c1="" appcreatereport="">
<tr _ngcontent-iji-c1="">
<td _ngcontent-iji-c1="">1</td>
<td _ngcontent-iji-c1="" id="A1" contenteditable="true" r="1" c="1"></td>
<td _ngcontent-iji-c1="" id="B1" contenteditable="true" r="1" c="2"></td>
<td _ngcontent-iji-c1="" id="C1" contenteditable="true" r="1" c="3"></td>
<td _ngcontent-iji-c1="" id="D1" contenteditable="true" r="1" c="4"></td>
<td _ngcontent-iji-c1="" id="E1" contenteditable="true" r="1" c="5"></td>
</tr>
...

Each <td>has an "id", a row number "r" and a column number "c"

I am trying to work with angular only (so no jquery) and I have looked at many existing data grids, but they are never fully covering what I plan to do and extending them seems more complicated than building exactly what I need.

I have two questions.

  1. My undertanding is that I am not supposed to manipulate the DOM directly in Angular, how can I access elements if they don't have a local reference ? (or how can I add a local reference when I generate the <td> elements in the renderer2. Text in <TD> will need to be updated, for example when I do a copy/paste from excel.
  2. How can I query an element by attributes, so I want the element where r=1 and c= 4 (instead of query by id "D1"). I only found @ViewChild which only works with references.

I am currently setting the text of a TD element the following way:

(document.getElementById(
          'C1'
        ) as HTMLTableDataCellElement).innerHTML = '123;

How can I do that in a more "Angular" way ?


Solution

  • The best way would be to change design to use table with array of elements and *ngFor. To remove it from the page you can use *ngIf="elements.length === 0";

    let elements = [{r:1, c: 1, value:''}, {r:1, c: 2, value:''} ... ];
    elements[1].value = '123';
    
    <td *ngFor="let el of elements" [r] = "el.r" [c]="el.c">{{el.value}}<\td>
    

    In such case you'll have access to each td values directly using elements array.

    As an alternative - ng-template can be used to keep table in html but not shown till needed.