角度HTML绑定


838

我正在编写Angular应用程序,并且要显示HTML响应。

我怎么做?如果我仅使用绑定语法,{{myVal}}那么它将编码所有HTML字符(当然)。

我需要以某种方式结合innerHTMLdiv对变量的值。


有关使组件中定义的CSS在HTML绑定中正确工作的相关文章stackoverflow.com/questions/36265026/…–
y3sh

1
我整理了一段视频,以解释该解决方案并给出示例:youtube.com/watch?v=Pem2UXp7TXA
Caleb Grams

如果变量保存角度标签或用户定义的标签(如<span [routerLink] = ['some-router']> link </ span>),该怎么办
G. Muqtada

Answers:


1332

正确的语法如下:

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

工作于 9.1.9

文档参考



14
有什么办法可以迫使angular在该innerHTML的元素上运行其绑定?我需要使用<a [router-link]="..."> </a>,并希望从外部html提供它。
thouliha '16

4
@thouliha我建议您开始撰写有关您问题的新文章。
prolink007

4
在我的情况下,它呈现字符串,但是对标记做了一些操作。似乎已经剥离了标记上的属性。我正在2.4.6
paqogomez

2
@paqogomez是的,它清除了任何它认为不安全的内容
Juan Mendes

311

Angular 2.0.0和Angular 4.0.0 final

为了安全起见

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

DOM Sanitizer

需要使用Angulars DOM清理器将潜在的不安全HTML明确标记为受信任,因此不会剥离内容的潜在不安全部分

<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-b​​rowser/DomSanitizer

安全警告

信任用户添加的HTML可能会带来安全风险。前面提到的文档状态:

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

角度标记

就像是

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

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

不会导致Angular在中处理任何特定于Angular的东西foo。Angular在生成时用生成的代码替换了Angular特定的标记。Angular不会处理在运行时添加的标记。

要添加包含Angular特定标记(属性或值绑定,组件,指令,管道等)的HTML,需要在运行时添加动态模块并编译组件。此答案提供了更多详细信息。如何使用/创建动态模板以使用Angular 2.0编译动态组件?


13
这应该是答案。注意注释掉的两行。实际上,它是处理HTML的第二个。
paqogomez

8
请确保import { BrowserModule, DomSanitizer } from '@angular/platform-browser'
paqogomez

4
另外import { Pipe } from '@angular/core'
阿普卢斯(Appulus)'17

1
这就是答案,就在这里!正在寻找有关NG2中什么代替NG1的$ SCE的详细信息。;)
jrista

2
好答案。解决了我的问题。非常感谢。如果有人不确定如何在组件中使用管道(就像我以前一样):angular.io/guide/pipes只需将其添加到相应模块中的声明中即可!
亚历杭德罗·纳吉

168

[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样式


1
除了您nativeElement直接访问的属性(这被认为是不好的做法)外,我与其他解决方案没有什么不同。我敢肯定[innerHTML]="...",在Angular2的实践中也做了相同的事情。
君特Zöchbauer

1
Angular2并不是这样工作的。添加到Angular2组件模板中的HTML首先由Angular处理,然后才添加到DOM。您实际上[innerHTML]在Angular2中遇到大型字符串的问题吗?
君特Zöchbauer

1
我认为这应该报告为错误。感谢您发布结果。
君特Zöchbauer

25
[innerHtml]删除HTML中硬编码的样式。为了集成所见即所得的编辑器,我不得不使用这里列出的方法。
乔尼·阿当密特

2
对我而言,此解决方案适用于包含内联SVG文档,而该[innerHTML]方法却没有。
Jared Phelps

52

在angular2@2.0.0-alpha.44上:

使用时,HTML绑定将不起作用{{interpolation}},请改用“表达式”:

无效

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

->引发错误(插值而不是期望的表达式)

正确

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

->这是正确的方法。

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

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

暗示

使用[innerHTML](或通过其他类似element.appenChild()或类似方式动态添加)添加的HTML 不会被Angular处理,除非出于安全目的进行了清理。
仅当将HTML静态添加到组件模板时,此类操作才起作用。如果需要,可以在运行时创建组件,如我如何使用/创建动态模板以使用Angular 2.0编译动态组件中所述。


1
再次尝试后进行了编辑。找到的解决方案:)
jvoigt

3
第三个示例不起作用。该表达式不求值。输出只是字符串...以其他方式将TrustedHTML与其他标签元素组合在一起吗?
凯文·维莱拉·平托

25

如果其中包含用户创建的内容,则不选择不使用Angular的DOM sanitizer而不直接使用[innerHTML]。@GünterZöchbauer 在他的回答中建议使用safeHtml管道,这是清理内容的一种方法。以下指令是另一个指令:

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>

我尝试使用此功能,但收到以下错误Can't bind to 'safeHtml' since it isn't a known property of 'div'. ng版本2.4.4
LearnToday

1
@ObasiObenyOj如果情况有限,您仍然可以在不使用单独指令的情况下执行此操作,constructor( private sanitizer: Sanitizer) {} 并将结果绑定到所需的内容中,强烈建议不要使用ElementRef。
Vale Steve

22

请参考其他最新的答案。

这对我<div innerHTML = "{{ myVal }}"></div>有用:(Angular2,Alpha 33)

根据另一种SO:使用angular2将服务器中的HTML插入DOM(Angular2中的一般DOM操作),“ inner-html”等效于Angular 1.X中的“ ng-bind-html”


正确的方法是没有{{}}:<div innerHTML =“ myVal”> </ div>
Christian Benseler

2
使用[属性]绑定语法代替{{interpolation}}
superluminary

这绝对是错误的方法,应予以否决。这将在div属性中呈现所有html!
AsGoodAsItGet

11

仅作一个完整的答案,如果您的html内容位于组件变量中,则还可以使用:

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

10

如果在这里我遗漏了一点,我深表歉意,但是我想推荐一种不同的方法:

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

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

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

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


28
在某些情况下,您肯定希望获取并显示原始html。例如,从远程获取格式化的文章。
亚历山大·陈

2
另一个经常被忽略的场景是保护模板中的业务逻辑,有时您不希望未经授权的用户看到用于显示信息的逻辑,因此您宁愿在服务器端准备视图
Ayyash

2
另外,显示HTML电子邮件,例如-公平点/问题!
达伦(Darren)

2
如果您错过了要点(您似乎已经承认了这一点),那么为什么要发表答复?显然,Angular的要点是使用其视图引擎来绑定和呈现数据。但是考虑到有无数的应用程序可以使用Angular应用程序这一事实,实际上可行的是,其中一个或两个应用程序要求某些需要在应用程序中显示的数据可能已经被格式化为HTML,开发人员无法控制该内容可能只是这种情况。换句话说...相关问题。
格雷戈尔

是的,我们应该抛弃Angular并使用JQuery,因为Jquery可以更好地完成这一件事...
Simon_Weaver

8

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

但是,此处提到的其他建议可能会产生误导。当您绑定到诸如此类的属性时,Angular具有内置的清理机制。由于Angular不是专用的消毒库,因此对可疑内容过分热衷而不承担任何风险。例如,它将所有SVG内容清除为空字符串。

您可能会听到通过使用DomSanitizer方法将内容标记为安全来“清理”内容的建议bypassSecurityTrustXXX。还有建议使用管道来完成该任务,该管道通常称为safeHtml

所有这些都具有误导性,因为它实际上绕过了清理而不是清理您的内容。这可能是一个安全问题,因为如果您对用户提供的内容或不确定的任何内容执行此操作,则可能会遭受恶意代码攻击。

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

我已经为其创建了一个包装器库,以便可以轻松地与Angular一起使用:https : //github.com/TinkoffCreditSystems/ng-dompurify

它还有一个管道以声明方式清理HTML:

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

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

要记住的一件事是DOMPurify非常适合清理HTML / 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和服务器端优化环境。


5

只需[innerHTML]HTML中使用attribute,如下所示:

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

您的组件中是否曾经包含过一些需要在模板中显示的html标记或实体的属性?传统的插值将不起作用,但是innerHTML属性绑定可以解决。

使用{{myVal}} 不能按预期工作!这会不会拿起像HTML标签<p><strong>等,它通过只作为字符串...

假设您的组件中包含以下代码:

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

如果使用{{myVal}},您将在视图中获得此信息:

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

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

计算器有帮助的!


如果没有该容器div,如何显示内容?那可能吗?
ΕГИІИО

2

您可以为.html中的样式,链接和HTML应用多个管道

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

“ HTML”消毒剂的管道

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

这将在不影响任何样式和链接点击事件的情况下都适用


2

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

innerHTML的是HTML的元素,它允许你设置它的HTML内容编程的特性。还有一个innerText属性,用于将内容定义为纯文本。

所述[attributeName]="value"框支架,围绕该属性定义的角输入结合。这意味着,属性的值(在您的情况下为innerHtml)绑定到给定的表达式,当expression-result更改时,属性值也更改。

因此,基本上[innerHtml]可以让您绑定并动态更改给定HTML元素的html内容。


1

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

  • [property]="expression"->任何html属性都可以链接到
    表达式。在这种情况下,如果expression changes属性将更新,但是反之则不行。
  • (event)="expression" ->事件激活时执行表达式。
  • [(ngModel)]="property"->将属性从js(或ts)绑定到html。此属性的任何更新都将在任何地方引起注意。

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

这里的例子


0

在AngularJS v2.1.1中工作

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

2
这产生了: <div _ngcontent-luf-0=""></div>对我来说。该div是空的。
Scott Marcus

0

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

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

指示

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

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

  constructor(public viewContainerRef: ViewContainerRef) { }

}

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

的HTML

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

然后,从注入的组件代码中,将注入包含所需HTML的组件:

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演示中


0

您可以使用多种方法来实现该解决方案。如已批准的答案中所述,您可以使用:

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

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

介绍

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

零件

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

属性绑定

Javascript DOM外部HTML


无论DOM操作是否比角度操作都慢,使用getElementsById或任何其他选择方法进行操作都是不好的,因为如果它们包含具有相同id(或其他条件)的元素,则它们可能捕获属于完全不同的组件的元素。
Aviad P.

另外,它完全可以在任何角度区域之外执行,因此不会发生变化。
菲利普·迈斯纳

0

我们总是可以将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>

即使您可能认为并非如此,这也是必要的。例如style: background-color,所有东西都可能被剥夺,因此最好一开始就开始使用它,否则以后会感到非常困惑。
Simon_Weaver

我了解的是,此脚本允许所有恶意内容(bypassSecurityTrustHtml),正如您指出的那样,除非您信任源,否则我认为不需要此管道。referto:angular.io/api/platform-b​​rowser/DomSanitizer#security-risk

0

如果您希望在Angular 2或Angular 4中使用它,并且还希望保留内联CSS,则可以使用

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

这给了我一个错误`未捕获的(在承诺):错误:模板解析错误:管道“keepHtml”不能found`
普利文

从“ @ angular / core”导入{Pipe,PipeTransform};
Jay Momaya


-2

如果在角度(或任何框架)应用程序中有模板,并且您通过HTTP请求/响应从后端返回HTML模板,则您在前端和后端之间混合了模板。

为什么不只将模板化的东西留在前端(我建议这样做)还是留在后端(相当不透明的imo)?

而且,如果您将模板保留在前端,为什么不只使用JSON响应对后端的请求。您甚至不必实现RESTful结构,但是将模板放在一边可以使您的代码更加透明。

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

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

哲学,人:)

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

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


有时,在处理SOAP中的旧API时,有必要从服务器端获取HTML。我在BSC(巴拉特证券交易所)的一个项目中工作,他们在付款时返回银行页面的HTML代码。因此,您无法更改其API,因此必须相应地更新代码。
Mahendra Waykos

您可以编写一个经常查询soap api的中间件,并在套接字中提供提取的结果。通过肥皂消费和提取信息可能会很痛苦。
Guntram '18 -4-12

原始标记的真正明显的用例是当标记来自CMS并由WYSIWYG编辑器编写时。例如,您可能正在从无头CMS服务多个端点。这就是为什么每个模板引擎都可以选择原始标记的原因。
gburton
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.