Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular HTML binding

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 encodes all HTML characters (of course).

I need somehow to bind the innerHTML of a div to the variable value.

like image 960
Aviad P. Avatar asked Jul 21 '15 19:07

Aviad P.


People also ask

How do I display HTML inside an Angular binding?

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?

Can I use innerHTML in Angular?

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. In this article, you will be presented with how to use [innerHTML] and some considerations for usage.

What is Ng bind HTML?

The ng-bind-html directive is a secure way of binding content to an HTML element.

What is binding in Angular?

Data binding in AngularJS is the synchronization between the model and the view. When data in the model changes, the view reflects the change, and when data in the view changes, the model is updated as well.


14 Answers

The correct syntax is the following:

<div [innerHTML]="theHtmlString"></div>

Documentation Reference

like image 173
prolink007 Avatar answered Oct 07 '22 17:10

prolink007


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?

like image 27
Günter Zöchbauer Avatar answered Oct 07 '22 17:10

Günter Zöchbauer


[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

like image 30
Piotrek Avatar answered Oct 07 '22 18:10

Piotrek


On [email protected]:

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?

like image 32
jvoigt Avatar answered Oct 07 '22 18:10

jvoigt


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>
like image 45
Rene Hamburger Avatar answered Oct 07 '22 19:10

Rene Hamburger


Please refer to other answers that are more up-to-date.

This works for me: <div innerHTML = "{{ myVal }}"></div> (Angular2, Alpha 33)

According to another SO: Inserting HTML from server into DOM with angular2 (general DOM manipulation in Angular2), "inner-html" is equivalent to "ng-bind-html" in Angular 1.X

like image 41
Fan Li Avatar answered Oct 07 '22 18:10

Fan Li


Just to make for a complete answer, if your HTML content is in a component variable, you could also use:

<div [innerHTML]=componentVariableThatHasTheHtml></div>
like image 36
Serj Sagan Avatar answered Oct 07 '22 17:10

Serj Sagan


I apologize if I am missing the point here, but I would like to recommend a different approach:

I think it's better to return raw data from your server side application and bind it to a template on the client side. This makes for more nimble requests since you're only returning json from your server.

To me it doesn't seem like it makes sense to use Angular if all you're doing is fetching html from the server and injecting it "as is" into the DOM.

I know Angular 1.x has an html binding, but I have not seen a counterpart in Angular 2.0 yet. They might add it later though. Anyway, I would still consider a data api for your Angular 2.0 app.

I have a few samples here with some simple data binding if you are interested: http://www.syntaxsuccess.com/viewarticle/angular-2.0-examples

like image 20
TGH Avatar answered Oct 07 '22 17:10

TGH


Short answer was provided here already: use <div [innerHTML]="yourHtml"> binding.

However the rest of the advices mentioned here might be misleading. Angular has a built-in sanitizing mechanism when you bind to properties like that. Since Angular is not a dedicated sanitizing library, it is overzealous towards suspicious content to not take any risks. For example, it sanitizes all SVG content into empty string.

You might hear advices to "sanitize" your content by using DomSanitizer to mark content as safe with bypassSecurityTrustXXX methods. There are also suggestions to use pipe to do that and that pipe is often called safeHtml.

All of this is misleading because it actually bypasses sanitizing, not sanitizing your content. This could be a security concern because if you ever do this on user provided content or on anything that you are not sure about — you open yourself up for a malicious code attacks.

If Angular removes something that you need by its built-in sanitization — what you can do instead of disabling it is delegate actual sanitization to a dedicated library that is good at that task. For example — DOMPurify.

I've made a wrapper library for it so it could be easily used with Angular: https://github.com/TinkoffCreditSystems/ng-dompurify

It also has a pipe to declaratively sanitize HTML:

<div [innerHtml]="value | dompurify"></div>

The difference to pipes suggested here is that it actually does do the sanitization through DOMPurify and therefore work for SVG.

One thing to keep in mind is DOMPurify is great for sanitizing HTML/SVG, but not CSS. So you can provider Angular's CSS sanitizer to handle CSS:

import {NgModule, ɵ_sanitizeStyle} from '@angular/core';
import {SANITIZE_STYLE} from '@tinkoff/ng-dompurify';

@NgModule({
    // ...
    providers: [
        {
            provide: SANITIZE_STYLE,
            useValue: ɵ_sanitizeStyle,
        },
    ],
    // ...
})
export class AppModule {}

It's internal — hense ɵ prefix, but this is how Angular team use it across their own packages as well anyway. That library also works for Angular Universal and server side renedring environment.

like image 32
waterplea Avatar answered Oct 07 '22 17:10

waterplea


Just simply use [innerHTML] attribute in your HTML, something like this below:

<div [innerHTML]="myVal"></div>

Ever had properties in your component that contain some html markup or entities that you need to display in your template? The traditional interpolation won't work, but the innerHTML property binding comes to the rescue.

Using {{myVal}} Does NOT work as expected! This won't pick up the HTML tags like <p>, <strong> etc and pass it only as strings...

Imagine you have this code in your component:

const myVal:string ='<strong>Stackoverflow</strong> is <em>helpful!</em>'

If you use {{myVal}}, you will get this in the view:

<strong>Stackoverflow</strong> is <em>helpful!</em>

but using [innerHTML]="myVal"makes the result as expected like this:

Stackoverflow is helpful!

like image 26
Alireza Avatar answered Oct 07 '22 18:10

Alireza


 <div [innerHTML]="HtmlPrint"></div><br>

The innerHtml is a property of HTML-Elements, which allows you to set it’s html-content programatically. There is also a innerText property which defines the content as plain text.

The [attributeName]="value" box bracket , surrounding the attribute defines an Angular input-binding. That means, that the value of the property (in your case innerHtml) is bound to the given expression, when the expression-result changes, the property value changes too.

So basically [innerHtml] allows you to bind and dynamically change the html-conent of the given HTML-Element.

like image 33
Supriya Avatar answered Oct 07 '22 17:10

Supriya


You can apply multiple pipe for style, link and HTML as following in .html

<div [innerHTML]="announcementContent | safeUrl| safeHtml">
                    </div>

and in .ts pipe for 'URL' sanitizer

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

@Pipe({ name: 'safeUrl' })
export class SafeUrlPipe implements PipeTransform {
    constructor(private sanitizer: DomSanitizer) {}
    transform(url) {
        return this.sanitizer.bypassSecurityTrustResourceUrl(url);
    }
}

pipe for 'HTML' sanitizer

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

@Pipe({
    name: 'safeHtml'
})
export class SafeHtmlPipe implements PipeTransform {
    constructor(private sanitized: DomSanitizer) {}
    transform(value) {
        return this.sanitized.bypassSecurityTrustHtml(value);
    }
}

this will apply both without disturbing any style and link click event

like image 44
Sahil Ralkar Avatar answered Oct 07 '22 19:10

Sahil Ralkar


In Angular 2 you can do 3 types of bindings:

  • [property]="expression" -> Any html property can link to an
    expression. In this case, if expression changes property will update, but this doesn't work the other way.
  • (event)="expression" -> When event activates execute expression.
  • [(ngModel)]="property" -> Binds the property from js (or ts) to html. Any update on this property will be noticeable everywhere.

An expression can be a value, an attribute or a method. For example: '4', 'controller.var', 'getValue()'

Example here

like image 37
adrisons Avatar answered Oct 07 '22 18:10

adrisons


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

like image 35
Jasdeep Singh Avatar answered Oct 07 '22 18:10

Jasdeep Singh