4
votes

In my Angular 7 app I have a simple home component using one-way data binding on a string variable (i.e. I pass a variable to a child component using @Input with the [text]="'Some text'" syntax).

I would like to include html tags such as links in the variable and render it in the child component but the code below fails because of the anchor tag. How to fix this?

home.component.ts:

{ Component } from '@angular/core';
@Component({
  selector: 'app-home',
  template: '
    <app-card [text]="'Some text and a link: <a href="https://stackoverflow.com" target="_blank">link</a>'">
    </app-card>
  ',
  styleUrls: ['./home.component.css']
})
export class HomeComponent {}

card.component.ts:

import { Component, Input } from '@angular/core';
@Component({
  selector: 'app-card',
  template: '
    <div class="bla bla">
      <p>{{text}}</p>
    </div>
  ',
  styleUrls: ['./card.component.css']
})
export class CardComponent {
  @Input() text: string;
}

Edit: I wrote 'templateUrl' but that was wrong, I mean 'template'. Let me add that my real card template is more complicated than the div shown here, and I actually use templateUrl in both components as follows:

templateUrl: './about.component.html', //in app component

templateUrl: './card.component.html',  //in card component
5
have you tryed like this [text]="{key: 'sdbjvbjhbvsdbv'}"? - Abhishek
i'm not giving you down votes - Abhishek
@Abhishek Thanks, your proposed solution gives [Object object] or so - aless80
have you try text.key for get value? - Abhishek
Thanks but I do not think your approach will help, cause I think the problem is writing a string with all the quotes as the following in my html template: "'Some text and a link: <a href="stackoverflow.com" target="_blank">link</a>'" - aless80

5 Answers

16
votes

I actually found how to do it. First, I needed to use innerHTML for the

element:

<p innerHTML={{text}}>{{text}}</p>

Second, some funky syntax. In the parent Home component notice that href and target attributes do not need quotes:

<app-card [text]="'Some text and a link: <a href=https://stackoverflow.com target=_blank>link</a>'">
</app-card>

Edit: Other users point to DOMSanitizer, but that forces me to write the text in the typescript part of the app component, not in the template part. As @John Velasquez says in another answer, this "solution is more likely a constant that cannot be changed anymore its more likely a one-way binding."

9
votes

This is by far the best and cleanest way to do it

Angular 2: Display HTML without sanitizing/filtering

1) Create new file to hold the pipe pipes/keep-html.pipe.ts:

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';

    @Pipe({ name: 'keepHtml', pure: false })

export class EscapeHtmlPipe implements PipeTransform {
  constructor(private sanitizer: DomSanitizer) {
  }

  transform(content) {
    return this.sanitizer.bypassSecurityTrustHtml(content);
  }
}

2) Add an import statement in your app.module.ts:

import { EscapeHtmlPipe } from './pipes/keep-html.pipe';
@NgModule({
  declarations: [
    EscapeHtmlPipe
  ],
  bootstrap: [AppComponent]
})
export class AppModule {
}

3) Finally use that pipe in your template:

<div [innerHTML]="post.body | keepHtml"></div>

👏 Kudos to Ammar Alakka for sharing this solution 👏.

4
votes

use DomSanitizer to bypass html

import { Component, Input } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
  selector: 'app-card',
  templateUrl: '
    <p [innerHtml]="result"></p>
  ',
  styleUrls: ['./card.component.css']
})
export class CardComponent implements OnInit {
  @Input() text: string;

  result: any;
  constructor(private sanitized: DomSanitizer) {

  }

  ngOnInit() {
    this.result = this.sanitized.bypassSecurityTrustHtml(this.text);
  }
}

see stackblitz for complete guide https://stackblitz.com/edit/angular-w6qys9

1
votes

for links you can use

<a [href]="text">Angular Docs</a>

If you want to pass a big html block, you'll need [innerHtml] https://angular.io/guide/template-syntax#property-binding-or-interpolation

See : https://angular.io/guide/ajs-quick-reference

1
votes

Try using DomSanitizer, bellow I give example where I used it for sanitizing a URL for use in iframe src property, but it also has a function to sanitize HTML:

import { DomSanitizer } from '@angular/platform-browser';
// ... then 
constructor(private sanitizer: DomSanitizer) {
}
// ... then (I used it with url, but it has an html sanitizer)
this.path = this.sanitizer.bypassSecurityTrustResourceUrl(this.sanitizer.sanitize(SecurityContext.URL, 'SOME_URL'));
// ... then in HTML
<iframe [src]="path"></iframe>