angularhtml-tableinnerhtmlangular15dangerouslysetinnerhtml

innerHtml in Angular 15 does'nt display correctly the <tr><td> data in each column of a html table


I'm trying to fill a html table with data (that I get from a http request) that are parsed in string. Like the string with data contains the <tr>/<td> markups, I'm trying to render them with the innerHtml of Angular. But all the data are displayed in the first column.

My request parse for fill the dataContent (the data for filled the html table):

const parser = new DOMParser();
const xml = parser.parseFromString(res.toString(), "text/xml");
this.dataContent = xml.querySelector("TABLEDATA")?.innerHTML;

How the dataContent looks like (with the right tr td markups, perfect for the [innerHtml] of Angular):

<TR><TD>[some data]</TD><TD>[some data]</TD>... </TR><TR>...</TR>...etc.

So I write it in the tbody of my html table with the innerHtml in purpose to filling each column with the dataContent:

<table id="first-table">
    <thead>
        <tr>
            <th>_id</th>
            <th>_time</th>
            <th>_ra</th>
            <th>_dec</th>
        </tr>
    </thead>
    <tbody [innerHtml]="dataContent"></tbody>
</table>

All the <tr><td> markups in the dataContent are processed (it's not showed up in the web page) BUT all the data are displayed only in the first column. The inspector view is like:

<tbody _ngcontent-fsr-c1="">
[all the data]
</tbody>

I develop the same web app in react and the unique difference in the code is instead of

<tbody [innerHtml]="dataContent"></tbody> // in Angular
<tbody dangerouslySetInnerHTML={{ __html: ref.current }}></tbody> // in React

And in React, it's work perfectly fine and, ref.current is exactly the same as dataContent.

What can be the problem then ?


Solution

  • I tried your solution and it gives me a "WARNING: sanitizing HTML stripped some content, see https://g.co/ng/security#xss". But despite this, it seems to display all my data (but it's not easy to be sure because I have a lot of data).

    So to handle this warning, I follow https://careydevelopment.us/blog/angular-how-to-deal-with-the-sanitizing-html-stripped-some-content-issue. We will write a pipe and we override Angular's default behavior. You need to be sure that will not be dangerous in your case.

    Create a nosanitizerpipe.ts file in a util folder. With this code in it:

    import { Pipe, PipeTransform } from '@angular/core';
    import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
    
    @Pipe({ name: 'noSanitize' })
    export class NoSanitizePipe implements PipeTransform {
      constructor(private domSanitizer: DomSanitizer) { }
    
      transform(html: string): SafeHtml {
        return this.domSanitizer.bypassSecurityTrustHtml(html);
      }
    }
    

    Import it in the module.ts:

    import { NoSanitizePipe } from '~/util/nosanitizepipe';
    

    And declare it:

    @NgModule({
      declarations: [
    ...
        NoSanitizePipe
      ]
    ...
    

    And use it like this in the template:

    <tbody [innerHtml]="dataContent | noSanitize"></tbody>
    

    Where dataContent isn't processed with sanitizeTableBody(bodyHtml: string) method.