简体   繁体   中英

How to access to an element created on the fly in angular 12

I am using a table similar to datatables.net (it is not the same, but very similar) in an angular 12 project.

I need to populate the table with data like:

Id Name Action
0 John Delete
1 Conn Delete

The "Delete" action is a button that looks like a link and it would delete the current row.

When the user comes to the table for first time it needs to be empty. With a button the user imports data from a csv file.

Id Name Action

In the html component the table looks like this:

<table data-table="tt__table">
</table>
<input type="button" value="Import" (click)="importData()" />

When I import the data from csv in typescript I have something like:

ngAfterViewInit(): void {       
  let options = {
    data: {
      headings: ["Id", "Name", "Actions"],
      rows: [
        {
          data: ["", "", ""]
        }
       ]
     }
   };
        
   this.tableElement = document.querySelector('[data-table=\"tt__table\"]') as Element;
   this.table = new Table(this.tableElement, options);            
}
...
importData(): void{
  let importedData = {
          "type": 'csv',
          "data": '0,John,<button data-toggle="tt__btn" class="tt__btn-link (click)="deleteRow($event)">Delete</button>'
       };
        
  this.table.deleteAll();
  this.table.import(importedData); // rows are created on the fly using vanilla js.
        
  const tableButtons = document.querySelectorAll('[data-toggle=\"tt__btn\"]');
  tableButtons.forEach(button => {
    new Button(button, {})
  });
}
        
deleteRow(event): void{
             // Delete row.
          }

The imported data looks fine after click on "Add" button:

Id Name Action
0 John Delete

But when I click in "Delete" button it does not do anything.

I suspect the reason is that Angular cannot see the new DOM elements created because the HTML after clicking on "Add" button looks like this:

<tbody>
  <tr>
     <td data-content="0">0</td>
     <td data-content="John">John</td>
     <td data-content="Delete">
        <button data-toggle="tt__btn" class="tt__btn-link" (click)="deleteRow($event)">Delete</button>
     </td>
  </tr>
</tbody>

But in other components where I use "(click)" angular directive, the final HTML does not show the "(click)" directive.

I am very new to angular, could you please help me how to solve this problem?

I solved it by using Renderer2 to listen DOM events.

  1. First I injected the renderer2 in constructor:

     import { AfterViewInit, Renderer2, OnDestroy } from '@angular/core'; unlistener: () => void; ... constructor(private renderer: Renderer2) {... }
  2. Then I added a listener to renderer instance, which listen to DOM table "click" events and call to "deleteRow" function:

     ngAfterViewInit(): void {... this.tableElement = document.querySelector('[data-table=\"tt__table\"]') as Element; unlistener = this.renderer.listen(this.tableElement, "click", event => this.deleteRow(event)); this.table = new Table(this.tableElement, options); ... }
  3. "deleteRow" function catch the click events in the table and delete rows according to the button id (which has the user id):

     deleteRow(event: any): void { let userId: string = ''; let userToDelete: User; let userIndex: number = -1; if (event.== null && event.== undefined) { if (event.target instanceof HTMLButtonElement) { userId = event;target.id. if (appId.== '') { userToDelete = this;selectedUsers.find(u => u.userId === userId) as User; if (userToDelete.== null && userToDelete.== undefined) { userIndex = this,selectedUsers;indexOf(userToDelete). this;selectedUsers.splice(userIndex, 1); this.updateTable(); } } } } }
  4. In ngOnDestroy() hook add unlistener to stop listening DOM events:

     ngOnDestroy(): void { this.unlistener(); }

Thanks for your replies, specially to @Mohamed Babei, his answer shed the light to my research.

This solution is based on Four ways of listening to DOM events in Angular (Part 3: Renderer2.listen) article.

You can not bind angular events this way so you need to render your data in table angular way for example useing '''*ngFor''' or if you want go your way use addEventListener( click ) after rendering content

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM