I am writing an Angular application and I have an HTML response I want to display.
How do I do that? If I simply use the binding syntax {{myVal}}
it en
[innerHtml]
is great option in most cases, but it fails with really large strings or when you need hard-coded styling in html.
I would like to share other approach:
All you need to do, is to create a div in your html file and give it some id:
<div #dataContainer></div>
Then, in your Angular 2 component, create reference to this object (TypeScript here):
import { Component, ViewChild, ElementRef } from '@angular/core';
@Component({
templateUrl: "some html file"
})
export class MainPageComponent {
@ViewChild('dataContainer') dataContainer: ElementRef;
loadData(data) {
this.dataContainer.nativeElement.innerHTML = data;
}
}
Then simply use loadData
function to append some text to html element.
It's just a way that you would do it using native javascript, but in Angular environment. I don't recommend it, because makes code more messy, but sometimes there is no other option.
See also Angular 2 - innerHTML styling
On angular2@2.0.0-alpha.44:
Html-Binding will not work when using an {{interpolation}}
, use an "Expression" instead:
invalid
<p [innerHTML]="{{item.anleser}}"></p>
-> throws an error (Interpolation instead of expected Expression)
correct
<p [innerHTML]="item.anleser"></p>
-> this is the correct way.
you may add additional elements to the expression, like:
<p [innerHTML]="'<b>'+item.anleser+'</b>'"></p>
hint
HTML added using [innerHTML]
(or added dynamically by other means like element.appenChild()
or similar) won't be processed by Angular in any way except sanitization for security purposed.
Such things work only when the HTML is added statically to a components template. If you need this, you can create a component at runtime like explained in How can I use/create dynamic template to compile dynamic Component with Angular 2.0?
Angular 2.0.0 and Angular 4.0.0 final
For safe content just
<div [innerHTML]="myVal"></div>
DOMSanitizer
Potential unsafe HTML needs to be explicitly marked as trusted using Angulars DOM sanitizer so doesn't strip potentially unsafe parts of the content
<div [innerHTML]="myVal | safeHtml"></div>
with a pipe like
@Pipe({name: 'safeHtml'})
export class Safe {
constructor(private sanitizer:DomSanitizer){}
transform(style) {
return this.sanitizer.bypassSecurityTrustHtml(style);
//return this.sanitizer.bypassSecurityTrustStyle(style);
// return this.sanitizer.bypassSecurityTrustXxx(style); - see docs
}
}
See also In RC.1 some styles can't be added using binding syntax
And docs: https://angular.io/api/platform-browser/DomSanitizer
Security warning
Trusting user added HTML may pose a security risk. The before mentioned docs state:
Calling any of the
bypassSecurityTrust...
APIs disables Angular's built-in sanitization for the value passed in. Carefully check and audit all values and code paths going into this call. Make sure any user data is appropriately escaped for this security context. For more detail, see the Security Guide.
Angular markup
Something like
class FooComponent {
bar = 'bar';
foo = `<div>{{bar}}</div>
<my-comp></my-comp>
<input [(ngModel)]="bar">`;
with
<div [innerHTML]="foo"></div>
won't cause Angular to process anything Angular-specific in foo
.
Angular replaces Angular specific markup at build time with generated code. Markup added at runtime won't be processed by Angular.
To add HTML that contains Angular-specific markup (property or value binding, components, directives, pipes, ...) it is required to add the dynamic module and compile components at runtime. This answer provides more details How can I use/create dynamic template to compile dynamic Component with Angular 2.0?
You can also bind the angular component class properties with template using DOM property binding.
Example: <div [innerHTML]="theHtmlString"></div>
Using canonical form like below:
<div bind-innerHTML="theHtmlString"></div>
Angular Documentation: https://angular.io/guide/template-syntax#property-binding-property
See working stackblitz example here
If you have templates in your angular (or whatever framework) application, and you return HTML templates from your backend through a HTTP request/response, you are mixing up templates between the frontend and the backend.
Why not just leave the templating stuff either in the frontend (i would suggest that), or in the backend (pretty intransparent imo)?
And if you keep templates in the frontend, why not just respond with JSON for requests to the backend. You do not even have to implement a RESTful structure, but keeping templates on one side makes your code more transparent.
This will pay back when someone else has to cope with your code (or even you yourself are re-entering your own code after a while)!
If you do it right, you will have small components with small templates, and best of all, if your code is imba, someone who doesn't know coding languages will be able to understand your templates and your logic! So additionally, keep your functions/methods as small you can. You will eventually find out that maintaining, refactoring, reviewing, and adding features will be much easier compared to large functions/methods/classes and mixing up templating and logic between the frontend and the backend - and keep as much of the logic in the backend if your frontend needs to be more flexible (e.g. writing an android frontend or switching to a different frontend framework).
Philosophy, man :)
p.s.: you do not have to implement 100% clean code, because it is very expensive - especially if you have to motivate team members ;) but: you should find a good balance between an approach to cleaner code and what you have (maybe it is already pretty clean)
check the book if you can and let it enter your soul: https://de.wikipedia.org/wiki/Clean_Code
Using [innerHTML] directly without using Angular's DOM sanitizer is not an option if it contains user-created content. The safeHtml pipe suggested by @GünterZöchbauer in his answer is one way of sanitizing the content. The following directive is another one:
import { Directive, ElementRef, Input, OnChanges, Sanitizer, SecurityContext,
SimpleChanges } from '@angular/core';
// Sets the element's innerHTML to a sanitized version of [safeHtml]
@Directive({ selector: '[safeHtml]' })
export class HtmlDirective implements OnChanges {
@Input() safeHtml: string;
constructor(private elementRef: ElementRef, private sanitizer: Sanitizer) {}
ngOnChanges(changes: SimpleChanges): any {
if ('safeHtml' in changes) {
this.elementRef.nativeElement.innerHTML =
this.sanitizer.sanitize(SecurityContext.HTML, this.safeHtml);
}
}
}
To be used
<div [safeHtml]="myVal"></div>