I have an interface:
export interface Project {
id: number;
name: string;
description: string;
previewHTMLElement: string;
}
That I use in a list:
export const PROJECTLIST: Project[] = [
{id: 1, name: 'a-cool-name', description: 'a cute description', previewHTMLElement: '<img src="assets/images/{{project.name}}.png">'}
]
That I am trying to use in an ngFor directive:
<div *ngFor="let project of projectList">
{{project.previewHTMLElement}}
</div>
But this is just replacing {{project.previewHTMLElement}}
with a #Text block that repeats whatever was in the string. I need to be able to put any kind of Element in the string and have it be rendered in as an actual HTMLElement.
What is the proper way to use angular directives to accomplish this goal?
CodePudding user response:
Angular 2 supports an [innerHTML]
property binding that will render HTML. If you were to otherwise use interpolation, it would be treated as a string.
I wouldn't trust anything to be used with innerHTML without cleaning it first. So, with DomSanitizer, a service of Angular helps to prevent attackers from injecting malicious client-side scripts into web pages, which is often referred to as Cross-site Scripting or XSS.
<div *ngFor="let project of projectList">
<span [innerHTML]="project.previewHTMLElement | sanitizeHtml"></span>
</div>
The sanitizer pipe
import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
@Pipe({ name: 'sanitizeHtml' })
export class sanitizeHtmlPipe implements PipeTransform {
constructor(private _sanitizer: DomSanitizer) {}
transform(value: string): SafeHtml {
return this._sanitizer.bypassSecurityTrustHtml(value);
}
}
Working example: https://stackblitz.com/edit/angular-pqwwes?file=app/app.component.html
CodePudding user response:
There are multiple ways to do this, some more interesting/recomended than others.
What you are trying wouldn't work, because interpolation will print stuff as a string...you could use the innerHTML property as a way to append the img tag as a child of your div, but this is considered a security risk.
Another way to do it is creating multiple templates within ng-template tags, using the correct elements for your use case and choosing one of them to render dynamically, passing the current ngFor element as a context variable (this article can help you understand how to achieve this)!
Cheers!