角度超文本标记语言绑定

我正在编写一个Angular应用程序,我有一个要显示的超文本标记语言响应。

我该怎么做?如果我简单地使用绑定语法{{myVal}},它会编码所有超文本标记语言字符(当然)。

我需要以某种方式将divinnerHTML绑定到变量值。

715877 次浏览

如果我错过了这一点,我很抱歉,但我想推荐一种不同的方法:

我认为最好从服务器端应用程序返回原始数据并将其绑定到客户端的模板。这使得请求更加灵活,因为你只从服务器返回json。

对我来说,如果您所做的只是从服务器获取html并将其“按原样”注入DOM,那么使用Angular似乎没有意义。

我知道Angular 1. x有一个html绑定,但我还没有看到Angular 2.0中的对应版本。不过他们可能会稍后添加它。无论如何,我仍然会考虑为您的Angular 2.0应用程序提供数据API。

如果您有兴趣,我这里有一些带有简单数据绑定的示例:http://www.syntaxsuccess.com/viewarticle/angular-2.0-examples

请参考其他更最新的答案。

<div innerHTML = "\{\{ myVal }}"></div>(Angular2,Alpha 33)

根据另一个SO:使用angular2将超文本标记语言从服务器插入DOM(Angular2中的一般DOM操作),“inner-html”等价于Angular 1. X中的“ng-bind-html”

关于angular2@2.0.0-alpha.44:

在使用\{\{interpolation}}时,Html-绑定将不起作用,请使用“表达式”代替:

无效

<p [innerHTML]="\{\{item.anleser}}"></p>

->抛出错误(插值而不是预期表达式)

正确

<p [innerHTML]="item.anleser"></p>

”””这是正确的方式。

您可以向表达式添加其他元素,例如:

<p [innerHTML]="'<b>'+item.anleser+'</b>'"></p>

提示

使用[innerHTML]添加的超文本标记语言(或通过element.appenChild()或类似的其他方式动态添加)不会以任何方式被Angular处理,除非出于安全目的进行清理。只有当超文本标记语言静态添加到组件模板时,这些东西才起作用。如果你需要,你可以在运行时创建一个组件,就像如何使用/创建动态模板来使用Angular 2.0编译动态组件?

中解释的那样

正确的语法如下:

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

文档参考

只是为了得到一个完整的答案,如果你的HTML内容在componentvariable中,你也可以使用:

<div [innerHTML]=componentVariableThatHasTheHtml></div>

在大多数情况下,[innerHtml]是一个很好的选择,但它在非常大的字符串或需要在html中硬编码样式时失败。

我想分享另一种方法:

您需要做的就是在html文件中创建一个div并给它一些id:

<div #dataContainer></div>

然后,在你的Angular 2组件中,创建对这个对象的引用(这里是TypeScript):

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;}}

然后只需使用loadData函数将一些文本附加到html元素。

这只是一种使用原生javascript的方式,但在Angular环境中。我不推荐它,因为会使代码更加混乱,但有时没有其他选择。

另见Angular 2-innerHTML样式

在Angular v2.1.1中工作

<div [innerHTML]="variable or htmlString"></div>

Angular 2.0.0和Angular 4.0.0最终版

对于安全内容只是

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

DOM消毒剂

潜在的不安全超文本标记语言需要使用Angulars DOM消毒剂显式标记为受信任,因此不会剥离内容中潜在的不安全部分

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

用管子像

@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}}

另见在RC.1中,不能使用绑定语法添加某些样式

文档:https://angular.io/api/platform-browser/DomSanitizer

安全警告

信任用户添加的超文本标记语言可能会带来安全风险。

调用任何bypassSecurityTrust... API都会禁用Angular对传入值的内置清理。仔细检查和审核进入此调用的所有值和代码路径。确保为此安全上下文适当转义了任何用户数据。有关更多详细信息,请参阅安全指南

角度标记

就像

class FooComponent {bar = 'bar';foo = `<div>\{\{bar}}</div><my-comp></my-comp><input [(ngModel)]="bar">`;

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

不会导致Angular在#0中处理任何Angular特定的东西Angular在构建时用生成的代码替换Angular特定的标记。在运行时添加的标记不会被Angular处理

要添加包含Angular特定标记(属性或值绑定、组件、指令、管道等)的超文本标记语言,需要在运行时添加动态模块和编译组件。这个答案提供了更多细节如何使用/创建动态模板来使用Angular 2.0编译动态组件?

如果[innerHTML]包含用户创建的内容,则直接使用[innerHTML]而不使用Angular的DOM清理器是不可行的。@GünterZöchbauer在他的回答建议的安全Html管道是清理内容的一种方法。以下指令是另一个:

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);}}}

要使用

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

角2中,您可以执行3种类型的绑定:

  • [property]="expression"->任何html属性都可以链接到
    表达式。在这种情况下,如果表达式更改属性将更新,但这种方法行不通。
  • (event)="expression"->当事件激活执行表达式时。
  • [(ngModel)]="property"->将属性从js(或ts)绑定到html。此属性的任何更新都将随处可见。

表达式可以是值、属性或方法。例如:'4'、'controller.var'、'getValue()'

示例这里

只需在超文本标记语言中使用[innerHTML]属性,如下所示:

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

您的组件中曾经有过包含一些html标记或需要在模板中显示的实体?传统的插值不起作用,但innerHTML属性绑定会《拯救》

使用\{\{myVal}}按预期工作!这个不会拿起超文本标记语言标签,如<p><strong>等,并仅将其作为字符串传递…

假设您的组件中有此代码:

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

如果你使用\{\{myVal}},你会在视图中得到这个:

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

但是使用[innerHTML]="myVal"会使结果像预期的那样:

堆栈溢出有用!

如Angular 2文档所述,动态向DOM添加元素的方法是使用@Angular/core中的ViewContainerRef类。

您要做的是声明一个指令,该指令将实现ViewContainerRef并充当DOM上的占位符。

指令

import { Directive, ViewContainerRef } from '@angular/core';
@Directive({selector: '[appInject]'})export class InjectDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}

然后,在要注入组件的模板中:

超文本标记语言

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

然后,从注入的组件代码中,您将注入包含所需超文本标记语言的组件:

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();}
}

我在Angular 2动态向DOM演示添加组件上添加了一个完全工作的演示应用程序

如果您的角度(或任何框架)应用程序中有模板,并且您通过HTTP请求/响应从后端返回超文本标记语言模板,则您正在混淆前端和后端之间的模板。

为什么不把模板的东西留在前端(我建议),或者在后端(相当不透明的imo)?

如果你把模板放在前端,为什么不直接用JSON响应后端的请求呢?你甚至不必实现RESTful结构,但是把模板放在一边会让你的代码更加透明。

当其他人不得不处理您的代码时(甚至您自己在一段时间后重新输入自己的代码),这将得到回报!

如果你做得对,你将拥有带有小模板的小组件,最重要的是,如果你的代码是imba,不懂编码语言的人将能够理解你的模板和逻辑!所以另外,保持你的函数/方法尽可能小。您最终会发现,与大型函数/方法/类相比,维护、重构、审查和添加功能要容易得多,并且在前端和后端之间混淆模板和逻辑-如果您的前端需要更灵活(例如编写android前端或切换到不同的前端框架),请将尽可能多的逻辑保留在后端。

哲学,男人:)

附注:您不必实现100%干净的代码,因为它非常昂贵-特别是如果您必须激励团队成员;)但是:你应该在更干净的代码方法和你拥有的代码之间找到一个很好的平衡(也许它已经很干净了)

如果可以,请检查这本书,让它进入你的灵魂:https://de.wikipedia.org/wiki/Clean_Code

你可以使用几种方法来实现解决方案。正如已经在批准的答案中所说,你可以使用:

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

根据您想要实现的目标,您还可以尝试其他东西,例如javascript DOM(不推荐,DOM操作很慢):

演示文稿

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

组件

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

属性绑定

JavaScript DOM超文本标记语言

我们总是可以将html内容传递给innerHTML属性来呈现html动态内容,但是动态html内容也可能被感染或恶意。因此,在将动态内容传递给innerHTML之前,我们应该始终确保内容被清理(使用DOMSanitizer),以便我们可以转义所有恶意内容。

试试下面的管道:

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>

如果你想在Angular 2或Angular 4中使用它,并且还想保持内联CSS,那么你可以使用

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

您可以为样式、链接和超文本标记语言应用多个管道,如下所示

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

和. ts管道中的“URL”消毒剂

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);}}

超文本标记语言消毒剂管道

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);}}

这将适用于不干扰任何样式和链接点击事件

这里已经提供了简短的答案:使用<div [innerHTML]="yourHtml">绑定。

然而,这里提到的其余建议可能是误导的。当你绑定到这样的属性时,Angular有一个内置的清理机制。由于Angular不是一个专用的清理库,它对可疑内容过于热心,不承担任何风险。例如,它将所有SVG内容清理为空字符串。

您可能会听到使用DomSanitizer将内容标记为bypassSecurityTrustXXX方法安全的建议来“净化”您的内容。也有建议使用管道来做到这一点,该管道通常称为safeHtml

所有这些都是误导性的,因为它实际上旁路消毒,而不是对您的内容进行消毒。这可能是一个安全问题,因为如果您对用户提供的内容或任何您不确定的内容执行此操作-您将为恶意代码攻击打开大门。

如果Angular通过其内置的清理删除了你需要的东西-你可以做的不是禁用它,而是将实际的清理委托给擅长该任务的专用库。例如-DOMPurify。

我为它做了一个包装器库,所以它可以很容易地与Angular一起使用:https://github.com/TinkoffCreditSystems/ng-dompurify

它还有一个管道来声明地清理超文本标记语言:

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

这里建议的管道的不同之处在于,它实际上通过DOMPurify进行消毒,因此适用于SVG。

需要记住的一件事是DOMPurify非常适合清理超文本标记语言/SVG,但不是CSS。所以你可以提供Angular的CSS清理器来处理CSS:

import {NgModule, ɵ_sanitizeStyle} from '@angular/core';import {SANITIZE_STYLE} from '@tinkoff/ng-dompurify';
@NgModule({// ...providers: [{provide: SANITIZE_STYLE,useValue: ɵ_sanitizeStyle,},],// ...})export class AppModule {}

它是内部的-henseɵ前缀,但这就是Angular团队在他们自己的包中使用它的方式。该库也适用于Angular Universal和服务器端renedring环境。

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

您还可以将角度组件类属性与模板使用DOM属性绑定绑定。

示例:<div [innerHTML]="theHtmlString"></div>

使用规范形式,如下所示:

<div bind-innerHTML="theHtmlString"></div>

Angular文档:https://angular.io/guide/template-syntax#property-binding-property

查看工作stackblitz这里的例子

只是为了发布到目前为止所有优秀答案的一点补充:如果您正在使用[innerHTML]来渲染Angular组件并且对它不像我一样工作感到沮丧,请查看我为解决这个问题而编写的ngx动态挂钩库。

有了它,您可以从动态字符串/html而不影响安全加载组件。它实际上使用Angular的DOMSanitizer,就像[innerHTML]一样,但保留了加载组件的能力(以安全的方式)。

在行动中看到它在这个Stackblitz

您可以使用以下两种方式。

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

<div innerHTML="\{\{myVal}}"></div>

Angular 2+支持将呈现超文本标记语言的[innerHTML]属性绑定。如果您要使用插值,它将被视为字符串。

.html文件

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

.ts文件

theHtmlString:String = "enter your html codes here";

我有下面的构建库,这将有助于重新绑定html格式的绑定。请在下面找到使用此库的步骤。该库基本上允许在AOT中注入JIT编译器代码

  1. 安装库

    npm i angular-html-recompile
  2. 在文件中添加下面app.component.html代码

    <pk-angular-html-recompile *ngIf="template !== ''"[stringTemplate]="template"[data]="dataObject"></pk-angular-html-recompile>
  3. 在app.component.ts文件中使用下面的代码

    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 namebreak;case `Password`://Update password from main componentthis.comp[`cmpRef`].instance['Password'] = "Karthik";break;case `submit`://Get reference of all parameters on submit click//1. respose.data OR//use this.comp[`cmpRef`].instancebreak;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 directivereturn true;}}
  4. 添加模块到app.module.ts文件

    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. 这个库支持基本的html、Angular材质、flex布局。要使用此功能,请安装以下依赖项

    npm i -s @angular/material @angular/flex-layout