How to put rich text in the detail section of angular master/detail collapsible table?

112 Views Asked by At

I have an angular master/detail collapsible table, as shown below: enter image description here

Notice that the text in the detail section is one big paragraph. I want for it to be formatted html instead. There need to be line breaks, bullet and numbered lists, fonts, italic, bold, etc.

The problem is that the number of master table rows are variable, so they are populated using angular *ngFor, or similar. In truth, I am using a third-party library called DevExtreme, but any method is gonna have the same problem. Here is that code:

<dx-data-grid
  id="gridContainer"
  [dataSource]="nutrients"
  [showBorders]=true
>>
  <dxo-scrolling mode="infinite"></dxo-scrolling>
  <dxo-paging [enabled]="false"></dxo-paging>
  <dxi-column dataField="name">Name</dxi-column>
  <dxi-column dataField="unitName">Unit Name</dxi-column>
  <dxi-column dataField="rda">RDA</dxi-column>
  <dxo-master-detail [enabled]="true" template="detail"></dxo-master-detail>

  <div class="info" *dxTemplate="let nutrient of 'detail'; let i = index;">
    {{ nutrient.data.info }}
  </div>
</dx-data-grid>

The associated detail text in the database is not formatted. If I try to add tags, like <p> they show up in the text literally. I think I need to store the text as markdown but then I don't know how to display it in the detail section.

I've googled for hours but can't find a solution. Any ideas?

3

There are 3 best solutions below

0
tekknow On BEST ANSWER

The solution was simple, as I thought it had to be. Simply use

<div class="info" *dxTemplate="let nutrient of 'detail';" [innerHtml]="nutrient.data.info">
</div>

The [innerHtml] directive was the key.

2
Tyurker Antonov On

The issue you have is that you are not passing the value as SafeHtml. Angular has a security mechanism to avoid injections. But if you know the source you can mark it as safe by byPassing it and setting it as innerHTML.

Here is the correct way to do it.

Html:

<div *ngFor="let htmlInsertionContent of htmlInsertionContents; let index = index">
  <div [innerHTML]="htmlInsertionContent" ></div>
</div>

ts:

import { Component, OnInit } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss'],
})
export class TestComponent implements OnInit{
  htmlInsertionContents: SafeHtml[]= [];

  constructor(private sanitizer: DomSanitizer) {
  }

  ngOnInit(): void {
    this.asyncData().subscribe((value) => {
      value.forEach(v=>{
        this.htmlInsertionContents.push(this.sanitizer.bypassSecurityTrustHtml(`<h1>header tag</h1><hr><hr><p>${this.getRandomNumberString()}</p>`))
      })
    })
  }

  asyncData(): Observable<number[]> {
    return new Observable(observer => {
      setTimeout(()=>{
        observer.next([0,0,0,0,0,0])
      }, 3000)
    })
  }

  getRandomNumberString(): string {
    return Math.random().toString()
  }
}

More details on it: https://angular.io/api/platform-browser/DomSanitizer

0
Tyurker Antonov On

Here is another example that might be more useful.

HTML:

<ng-container *ngFor="let text of textArray; let index = index">
  <div [innerHTML]="convertIntoSafeHTML(text)" ></div>
</ng-container>

ts:

import { Component } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss'],
})
export class TestComponent {

  textArray: string[]= [
    `<h1>header tag</h1><hr><hr><p>${this.getRandomNumberString()}</p>`,
    `<h1>header tag</h1><hr><hr><p>${this.getRandomNumberString()}</p>`,
    `<h1>header tag</h1><hr><hr><p>${this.getRandomNumberString()}</p>`,
    `<h1>header tag</h1><hr><hr><p>${this.getRandomNumberString()}</p>`,
  ]

  constructor(private sanitizer: DomSanitizer) {
  }

  getRandomNumberString(): string {
    return Math.random().toString()
  }

  convertIntoSafeHTML(htmlAsString: string): SafeHtml {
    return this.sanitizer.bypassSecurityTrustHtml(htmlAsString)
  }
}