1083

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.

Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Aviad P.
  • 32,036
  • 14
  • 103
  • 124
  • 3
    Related post for getting CSS defined in a component to work right in the HTML binding https://stackoverflow.com/questions/36265026/angular-2-innerhtml-styling – Josh Hibschman Sep 11 '17 at 18:32

24 Answers24

1633

The correct syntax is the following:

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

Documentation Reference

Edric
  • 24,639
  • 13
  • 81
  • 91
prolink007
  • 33,872
  • 24
  • 117
  • 185
  • 23
    Is there any way I can force angular to run its binding on the elements of that innerHTML? I need to use an , and want to provide that from external html. – dessalines Apr 29 '16 at 22:04
  • 6
    It renders the string in my case, but does something to the markup. Seems to have stripped out attributes on markup . I'm on 2.4.6 – crthompson Mar 20 '17 at 23:10
  • In case you want the html to stick refer here... https://medium.com/@AAlakkad/angular-2-display-html-without-sanitizing-filtering-17499024b079 – siddharthrc Feb 16 '18 at 22:00
  • @prolink007 when you said "working in 7.0.2" what is that mean? That's the angular version? because the question was in Angular 2, I'm facing the same thing and I'm not getting the binding – napstercake Nov 07 '18 at 20:48
  • @RicardoGonzales There is no such thing as "angular 2" any more. There is angularjs and angular. When i say "working in 7.0.2", i mean it is working in that current version of "angular". Which version are you trying to use the binding in? – prolink007 Nov 07 '18 at 21:07
  • @prolink007 2.3.1 – napstercake Nov 08 '18 at 20:04
  • @RicardoGonzales As far as i know, the way listed in my answer should still be correct for that version of angular. – prolink007 Nov 08 '18 at 20:09
  • 2
    @thouliha did you ever find an answer? is there any way to force angular to reevaluate the bindings after the injection? all my bindings and templates are broken within the innerHtml portion – jgritten Jan 28 '19 at 18:46
  • Unfortunately not, I haven't found a way. – dessalines Jan 28 '19 at 20:34
  • 2
    The other answers https://stackoverflow.com/a/41089093/1225421 and https://stackoverflow.com/a/41121006/1225421 solve the security HTML sanitzer problem. – Alex P. Apr 08 '19 at 13:35
  • @thouliha, dynamic component creation can be the solution for this. Here, https://stackblitz.com/edit/angular-compile-directive , take a look at CompileDirective. It parses passed string as an anonymous component' template and appends this component to the current component. – lucifer63 Oct 29 '19 at 16:26
  • This works for me but when I navigate to other page and comes back again. html doesn't show on the page. I can still see it in console.log. Any ideas what could be the issue? – Nouman Bhatti Dec 09 '19 at 04:20
  • This obviously works but this will not append the html component rather it replaces (for instance I don't have an ngfor) so in order to append I used viewchild('id') with innerhtml and it worked. But now I had to use the same in the same component and Iam not allowed to use multiple viewchild(). So now I'm in search of some other option to append div data to html. Any help? – Akhil Dec 17 '19 at 03:36
  • 2
    @jgritten Have a look at https://www.npmjs.com/package/ngx-dynamic-hooks – J. Reynolds Aug 31 '20 at 12:30
  • @prolink007 can i render element from UI Library like Ant Design ? E.g : innerHtml = '...' – Quan Truong Sep 28 '22 at 03:07
  • Voted this down as it is not a complete answer. See @Günter Zöchbauer answer – GregJF Oct 14 '22 at 01:51
394

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?

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Useful for rendering HTML email bodies, as they tend to have styles embedded. – Darren Shewry Feb 06 '17 at 09:03
  • 21
    This should be the answer. Pay attention to the two lines that are commented out. It is actually the second one that handles HTML. – crthompson Mar 20 '17 at 23:28
  • 10
    be sure to `import { BrowserModule, DomSanitizer } from '@angular/platform-browser'` – crthompson Mar 20 '17 at 23:29
  • 6
    Also `import { Pipe } from '@angular/core'` – Appulus Mar 30 '17 at 09:37
  • [ts] Property 'bypassSecurityTrustHtml' does not exist on type 'Sanitizer'.? – Rolando Jul 16 '17 at 05:03
  • 2
    Use `DomSanitizer` instead – Günter Zöchbauer Jul 16 '17 at 09:31
  • 2
    This answer solves the problems generated by HTML consider unsafe. I managed to define text color and add a youtube `iframe` with it. You cannot achieve this by simply setting the innerHTML like it is descibed in the other answers. – Alex P. Apr 08 '19 at 13:31
  • 1
    @AlexPandrea hard to tell what exactly you were doing, but if you claim the content is safe (for example by using `| safeHtml`), then Angular trusts you and you are responsible. – Günter Zöchbauer Apr 08 '19 at 13:35
  • 1
    @GünterZöchbauer I was just applying your (great) solution to be able to bypass that security filter and define the type of mentioned content. I am not implying at all that this technique is safe - since it's clear that it bypasses a security layer. – Alex P. Apr 08 '19 at 13:46
  • angular does it automatically, but posts to the console https://angular.io/guide/security#sanitization-and-security-contexts – austin Feb 25 '20 at 23:05
  • 1
    This probably only isn't upvoted as much because it was a year later than the other answer https://stackoverflow.com/a/34424375/3177709 that says the same thing that this one starts with. That and people have a tendency to not scroll down, and to overlook longer answers. – RoboticRenaissance Sep 21 '21 at 15:02
  • 1
    Voted this up as it is a more complete answer. – GregJF Oct 14 '22 at 01:52
  • @GünterZöchbauer wen i added like this html is showing but (click) event is not triggering? – Mohammed Nov 11 '22 at 17:06
  • @Dojo you can't add Angular bindings this way, just plain HTML. You might want dynamic components or add event handlers imperatively. If you need support, please create a new question with full information. – Günter Zöchbauer Nov 12 '22 at 14:16
196

[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

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
Piotrek
  • 10,919
  • 18
  • 73
  • 136
  • 2
    Other solutions save string to html attribute first, than loads html. Saving large string to attribute causes browser freezes or even crashes. My solution omits this "attribute part" – Piotrek Aug 08 '16 at 10:36
  • 1
    Yep, otherwise I wouldn't add my answer here – Piotrek Aug 08 '16 at 10:47
  • 29
    `[innerHtml]` removes styling hard-coded in the Html. In order to integrate a wysiwyg editor, I had to use the approach listed here. – Jony Adamit Aug 14 '16 at 06:11
  • 1
    This is useful for generating content that will go into an HTML email where inline styling is unfortunately still necessary. Other methods using interpolation removed the inline styles. – Frank Aug 31 '16 at 17:35
  • An even more "correct" and decoupled way would be to access the element via the renderer and not directly on the nativeElement. Like described here: http://stackoverflow.com/a/38003377/2477307 – BobbyTables Nov 17 '16 at 09:32
  • in my case i had also use this approach because i want to set also styles and [innerHtml] cut them off. – Adrian Deja Dec 16 '16 at 08:30
  • When using the https://github.com/platosha/angular-polymer lib, then this is the only way at the moment to display dynamic HTML. – Marc Borni Feb 21 '17 at 08:36
  • 1
    Can this `@ViewChild` work for multiple div s? and if so, how? – Guram Feb 22 '17 at 12:07
  • Thanks for solution, partially worked. My html content has JS/Css links which is not rendering. Due to which I am getting my page broken, partially loaded. How can I fix that? Struggling last 1 day. @Piotrek – Pawan Mittal Aug 05 '17 at 16:07
  • Hi @PawanMittal, I personally haven't faced that kind of problem, but here is what I found after quick google search https://stackoverflow.com/a/39959424/1804027 . Seems that browser doesn't render it because of some safety reasons. – Piotrek Aug 07 '17 at 12:03
  • I used this approach with ionicv3 and tscv2.5 and it solved the problem in a way none of the other approaches listed here could. Thks – Nditah Jan 31 '18 at 11:39
  • Although this indeed works, even in Angular 8, I can't help but thinking like @GünterZöchbauer above, that this must be a bug in Angular, you shouldn't be able to bypass security so easily. – AsGoodAsItGets Mar 02 '20 at 17:40
  • That's intentional and it's your decision to use it. If you know the passed value is safe because no user input is involved or because it was handled by custom sanitization code, then it's safe to tell Angular it can render the value as-is. That's all it does. – Günter Zöchbauer Mar 02 '20 at 18:08
  • @GünterZöchbauer if Angular trusts me to know that the value is safe when used like this, why doesn't it also trust me when I use the `innerHTML` attribute directly in the template? – AsGoodAsItGets Mar 04 '20 at 10:00
  • Anglar just wants you to opt in explicitly. It's safe by default, no matter where the passed content comes from. If you need different behavior you can inform Angular that you know the content you pass is safe, which is often easy to say if for example it comes from string constants in your code. If you know the content is unsafe because it comes from user input, but you want to be more permissive than Angulars sanitizer, you can customize the sanitizer or build your own and notify Angular that the content was sanitized. – Günter Zöchbauer Mar 04 '20 at 10:47
  • @JonyAdamit you could've used DomSanitizer to stop angular from stripping off content before displaying. – Ε Г И І И О Apr 20 '20 at 12:59
  • @ΕГИІИО and that's what I did.. but with the approach listed here and not some of the other approaches listed in other answers. This was 4 years ago btw, didn't remember I even posted that comment :) – Jony Adamit Apr 21 '20 at 13:54
69

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?

jvoigt
  • 1,806
  • 1
  • 18
  • 22
  • 3
    The third example not working. The expression is not evaluate. The output is simply string... Any other way to combile trustedHTML with another tags elements ? – Kévin Vilela Pinto Dec 06 '16 at 08:41
30

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>
Community
  • 1
  • 1
Rene Hamburger
  • 2,003
  • 16
  • 17
  • 1
    @ObasiObenyOj you can still do that without the using of a separate directive if is a limited case, ```constructor( private sanitizer: Sanitizer) {} ```and bind the result into whatever you need, also the usage of ElementRef is strongly unsuggested. – Valex Feb 03 '17 at 11:58
  • Does it work with input and text-area elements? – SkogensKonung Feb 15 '21 at 16:16
29

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

Fan Li
  • 1,057
  • 7
  • 11
27

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

<div [innerHTML]=componentVariableThatHasTheHtml></div>
Serj Sagan
  • 28,927
  • 17
  • 154
  • 183
14

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.

EDIT: Angular no longer sanitizes CSS as of Ivy renderer so below info, kept for history sake, is irrelevant:

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 — hence ɵ 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 rendering environment.

waterplea
  • 3,462
  • 5
  • 31
  • 47
12

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

TGH
  • 38,769
  • 12
  • 102
  • 135
  • 30
    There's definitely use cases where you'd want to fetch and display raw html. E.g. fetching a formatted piece of article from remote. – Alexander Chen Dec 24 '15 at 02:17
  • 2
    Another often-ignored scenario is protecting the business logic in the template, you sometimes don't want unauthorized users to see the logic you are using to display information, so you would rather prepare the view on server side – Ayyash Feb 20 '16 at 11:45
  • 2
    If you are missing the point (which you seem to be by your own admission), then why post a response? Obviously the point of Angular is to use its view engine to bind and render the data. But considering the fact that there are countless applications where an Angular app might be used, it is actually feasible that one or two of them might have the requirement that some of the data that needs to be displayed in your application may already be formatted HTML, and it might just happen to be the case where the developer does not have control over that content. In other words... relevant question. – Gregor Nov 01 '17 at 05:50
7

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!

Alireza
  • 100,211
  • 27
  • 269
  • 172
7

 <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.

Hitech Hitesh
  • 1,641
  • 1
  • 9
  • 18
Supriya
  • 481
  • 5
  • 5
4

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

Sahil Ralkar
  • 2,331
  • 23
  • 25
2

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

Community
  • 1
  • 1
adrisons
  • 3,443
  • 3
  • 32
  • 48
2

We can always pass html content to innerHTML property to render html dynamic content but that dynamic html content can be infected or malicious also. So before passing dynamic content to innerHTML we should always make sure the content is sanitized (using DOMSanitizer) so that we can escaped all malicious content.

Try below pipe:

import { 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: string) {
        return this.sanitized.bypassSecurityTrustHtml(value);
    }
}

Usage:
<div [innerHTML]="content | safeHtml"></div>
Suneet Bansal
  • 2,664
  • 1
  • 14
  • 18
2

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

Jasdeep Singh
  • 7,901
  • 1
  • 11
  • 28
1

You can use the Following two ways.

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

or

<div innerHTML="{{myVal}}"></div>
Hasee Amarathunga
  • 1,901
  • 12
  • 17
1

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.

Into .html file

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

Into .ts file

theHtmlString:String = "enter your html codes here";
Tharindu Lakshan
  • 3,995
  • 6
  • 24
  • 44
1

I have build below library which will help to rebind html formatted bindings. Please find below steps to use this library. This library basically allows to inject JIT compilter code in AOT

  1. Install library using

    npm i angular-html-recompile
    
  2. Add below code in app.component.html file

    <pk-angular-html-recompile *ngIf="template !== ''" 
                               [stringTemplate]="template" 
                               [data]="dataObject"> 
    </pk-angular-html-recompile>
    
  3. Use below code in app.component.ts file

    import { Component, OnInit, ViewChild } from '@angular/core';
    import { AngularHtmlRecompileComponent, AngularHtmlRecompileService } from 'angular-html-recompile';
    
    @Component({
        selector: 'app-root',
        templateUrl: './app.component.html',
        styleUrls: ['./app.component.scss']
    })
    export class AppComponent implements OnInit {
    
        @ViewChild(AngularHtmlRecompileComponent, { static: true }) comp !: AngularHtmlRecompileComponent;
    
        constructor(
            private angularHtmlRecompileService: AngularHtmlRecompileService) {
        }
    
        public dataObject: any;
    
        public template = `<div class="login-wrapper" fxLayout="row" fxLayoutAlign="center center">
        <mat-card class="box">
            <mat-card-header>
            <mat-card-title>Register</mat-card-title>
            </mat-card-header>
            <form class="example-form">
            <mat-card-content>
                <mat-form-field class="example-full-width">
                <input matInput placeholder="Username" [value]="Username" (keydown)="onControlEvent($event,'Username')">
                </mat-form-field>
                <mat-form-field class="example-full-width">
                <input matInput placeholder="Email" [value]="Email" (keydown)="onControlEvent($event,'Email')">
                </mat-form-field>
                <mat-form-field *ngIf="isShow" class="example-full-width">
                <input matInput placeholder="Password" [value]="Password" (keydown)="onControlEvent($event,'Password')">
                </mat-form-field>
                <mat-form-field class="example-full-width">
                <mat-label>Choose a role...</mat-label>
                <mat-select (selectionChange)="onControlEvent($event, 'selectedValue')">
                    <mat-option [value]="roles" *ngFor="let roles of Roles">{{roles}}
                    </mat-option>
                </mat-select>
                </mat-form-field>
            </mat-card-content>
            <button mat-stroked-button color="accent" class="btn-block" (click)="buttomClickEvent('submit')" >Register</button>
            </form>
        </mat-card>
        </div>`;
    
        ngOnInit(): void {
    
            this.angularHtmlRecompileService.sharedData.subscribe((respose: any) => {
                if (respose) {
                    switch (respose.key) {
                        case `Username`:
                            // Call any method on change of name
                            break;
                        case `Password`:
                            //Update password from main component
                            this.comp[`cmpRef`].instance['Password'] = "Karthik";
                            break;
                        case `submit`:
                            //Get reference of all parameters on submit click
                            //1. respose.data OR
                            //use this.comp[`cmpRef`].instance
                            break;
                        default:
                            break;
                    }
                }
            });
    
            this.prepareData();
    
        }
    
        prepareData() {
    
            //Prepare data in following format only for easy binding
            //Template preparation and data preparation can be done once data received from service
    
            // AngularHtmlRecompileComponent will not be rendered until you pass data 
    
            this.dataObject = [
                { key: 'Username', value: 'Pranay' },
                { key: 'Email', value: 'abc@test.com', },
                { key: 'Password', value: 'test123', },
                { key: 'Roles', value: ['Admin', 'Author', 'Reader'] },
                { key: 'isShow', value: this.updateView() }
            ];
    
        }
    
        updateView() {
            //Write down logic before rendering to UI to work ngIf directive
            return true;
        }
    }
    
  4. Add module into app.module.ts file

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    
    import { AppComponent } from './app.component';
    import { AngularHtmlRecompileModule } from "angular-html-recompile";
    
    @NgModule({
        declarations: [
            AppComponent
        ],
        imports: [
            BrowserModule,
            AngularHtmlRecompileModule
        ],
        providers: [],
        bootstrap: [AppComponent]
    })
    export class AppModule { }
    
  5. This library supports basic html, Angular material, flex layouts. To use this features install below dependencies

    npm i -s @angular/material @angular/flex-layout
    
Josef
  • 2,869
  • 2
  • 22
  • 23
0

Working in Angular v2.1.1

<div [innerHTML]="variable or htmlString">
</div>
Edric
  • 24,639
  • 13
  • 81
  • 91
FACode
  • 951
  • 1
  • 11
  • 19
0

The way to dynamically add elements to DOM, as explained on Angular 2 doc, is by using ViewContainerRef class from @Angular/core.

What you have to do is to declare a directive that will implement ViewContainerRef and act like a placeholder on your DOM.

Directive

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appInject]'
})
export class InjectDirective {

  constructor(public viewContainerRef: ViewContainerRef) { }

}

Then, in the template where you want to inject the component:

HTML

<div class="where_you_want_to_inject">    
  <ng-template appInject></ng-template>
</div>

Then, from the injected component code, you will inject the component containing the HTML you want:

import { Component, OnInit, ViewChild, ComponentFactoryResolver } from '@angular/core';
import { InjectDirective } from '../inject.directive';
import { InjectedComponent } from '../injected/injected.component';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {

  @ViewChild(InjectDirective) injectComp: InjectDirective;

  constructor(private _componentFactoryResolver: ComponentFactoryResolver) {
  }

  ngOnInit() {
  }

  public addComp() {
    const componentFactory = this._componentFactoryResolver.resolveComponentFactory(InjectedComponent);
    const viewContainerRef = this.injectComp.viewContainerRef;
    const componentRef = viewContainerRef.createComponent(componentFactory);
  }

  public removeComp() {
    const componentFactory = this._componentFactoryResolver.resolveComponentFactory(InjectedComponent);
    const viewContainerRef = this.injectComp.viewContainerRef;
    const componentRef = viewContainerRef.remove();
  }

}

I added a fully working demo app on Angular 2 dynamically add component to DOM demo

BogdanC
  • 2,746
  • 2
  • 24
  • 22
0

You can use several approaches to achieve the solution. As already said in the approved answer, you can use:

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

depending on what you are trying to achieve, you can also try other things like javascript DOM (not recommended, DOM operations are slow):

Presentation

<div id="test"></test>

Component

var p = document.getElementsById("test");
p.outerHTML = myVal;

Property Binding

Javascript DOM Outer HTML

João Beirão
  • 1,431
  • 2
  • 9
  • 13
  • Regardless of whether DOM operations are slower than angular or not, doing it by using `getElementsById` or any other selection method is bad because it might capture elements belonging to completely different components if they contain elements with the same id (or other criteria). – Aviad P. Feb 26 '19 at 12:57
  • Plus it completely performs outside of any angular-zone so changes will not be picked up. – Philipp Meissner Jun 13 '19 at 10:05
0

If you want that in Angular 2 or Angular 4 and also want to keep inline CSS then you can use

<div [innerHTML]="theHtmlString | keepHtml"></div>
Jay Momaya
  • 1,831
  • 19
  • 32
0

Just to post a little addition to all the great answers so far: If you are using [innerHTML] to render Angular components and are bummed about it not working like me, have a look at the ngx-dynamic-hooks library that I wrote to address this very issue.

With it, you can load components from dynamic strings/html without compromising security. It actually uses Angular's DOMSanitizer just like [innerHTML] does as well, but retains the ability to load components (in a safe manner).

See it in action in this Stackblitz.

Mvin
  • 385
  • 4
  • 12
-2

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

Guntram
  • 961
  • 14
  • 19
  • -2 votes. Hah. Ok I will vote for this answer, just because it is obvious that other answers are almost the same. Although this answer doen't provide clean solution it is answer, that puts you in state of thinking, and not copy pasting someones solution.____ In my case I couldn't use this solution, because I had library on the backend that returns code that I have to display as inner html.If I have to move everything from that library, probably would cost me week or two. Sometimes is not possible. But may be I will move only the styles on client side, which may or may not solve my problem. – makkasi Dec 01 '20 at 18:44