关于Angular2模板:Angular HTML绑定

Angular HTML binding

我正在写一个角度应用程序,我有一个HTML响应,我想显示。

我该怎么做?如果我只使用绑定语法{{myVal}},它会对所有HTML字符进行编码(当然)。

我需要以某种方式将div的内部HTML绑定到变量值。


正确的语法如下:

1
 

在工作7.2.13

文件参考


角度2.0.0和角度4.0.0最终

为了安全的内容

1
 

多杀菌剂

潜在的不安全HTML需要使用angulars dom消毒剂显式标记为可信,这样就不会删除内容中潜在的不安全部分。

1
 

像管子一样

1
2
3
4
5
6
7
8
9
10
@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

安全警告

信任用户添加的HTML可能会带来安全风险。上述文件说明:

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.

角标记

类似的东西

1
2
3
4
5
class FooComponent {
  bar = 'bar';
  foo = `{{bar}}
    <my-comp></my-comp>
    <input [(ngModel)]="bar">`;

具有

1
 

不会导致角处理任何特定于foo的角。Angular在构建时用生成的代码替换特定于Angular的标记。运行时添加的标记不会由Angular处理。

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


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

我想分享其他方法:

您所需要做的就是在HTML文件中创建一个DIV并给它一些ID:

1
 

然后,在Angular2组件中,创建对该对象的引用(此处为typescript):

1
2
3
4
5
6
7
8
9
10
11
12
13
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 2-InnerHTML样式


[email protected]上:

使用{{interpolation}}时,HTML绑定将不起作用,请使用"表达式"代替:

无效

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

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

对的

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

->这是正确的方法。

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

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

暗示

使用[innerHTML]添加的HTML(或通过其他方式动态添加,如element.appenChild()或类似方式)将不会以任何方式由Angular处理,除非出于安全目的进行了消毒。只有当HTML静态添加到组件模板中时,这些功能才起作用。如果需要,您可以在运行时创建一个组件,就像我如何使用/创建动态模板来编译角度为2.0的动态组件中所解释的那样?


如果包含用户创建的内容,则不使用Angular的DOM消毒剂直接使用[InnerHTML]不是一个选项。@g_ntez建议的safehtml管道?在他的回答中,chbauer是一种净化内容的方法。以下指令是另一个指令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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);
    }
  }
}

被使用

1
 


这对我有用:(angular2,alpha 33)

另一种说法是:使用angular2(angular2中的一般dom操作)将html从服务器插入到dom中,"inner html"相当于angular1.x中的"ng bind html"。


为了得到一个完整的答案,如果您的HTML内容在一个组件变量中,您还可以使用:

1
 

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

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

在我看来,如果您所做的只是从服务器获取HTML并将其"原样"注入到DOM中,那么使用Angular似乎没有意义。

我知道Angular1.x有一个HTML绑定,但我还没有在Angular2.0中看到对应的绑定。不过,他们稍后可能会添加。不管怎样,我仍然会考虑为您的Angular2.0应用程序提供一个数据API。

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


只需在HTML中使用[innerHTML]属性,如下所示:

1
 

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.

使用{{myVal}}不能按预期工作!这不会拾取诸如

等HTML标记,只将其作为字符串传递…

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

const myVal:string ='Stackoverflow is helpful!'

如果您使用{{myVal}},您将看到:

1
Stackoverflow is helpful!

但是使用[innerHTML]="myVal"可以得到预期的结果:

StackOverflow很有用!


在Angular2中,可以执行3种类型的绑定:

  • [property]="expression"->任何HTML属性都可以链接到表达式。在这种情况下,如果表达式更改属性将更新,但这不起作用。
  • 当事件激活执行表达式时,(event)="expression"->
  • [(ngModel)]="property"->将JS(或TS)的属性绑定到HTML。任何有关此属性的更新都会在任何地方引起注意。

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

这里例子


我们总是可以将HTML内容传递给innerHTML属性以呈现HTML动态内容,但动态HTML内容也可能受到感染或恶意攻击。因此,在将动态内容传递给innerHTML之前,我们应该始终确保对内容进行了清理(使用DOMSanitizer),以便能够避免所有恶意内容。

尝试以下管道:

1
2
3
4
5
6
7
8
9
10
11
12
13
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:


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

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

指令

1
2
3
4
5
6
7
8
9
10
import { Directive, ViewContainerRef } from '@angular/core';

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

  constructor(public viewContainerRef: ViewContainerRef) { }

}

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

HTML

1
  <ng-template appInject></ng-template>

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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();
  }

}

我在Angular2上添加了一个完全工作的演示应用程序,动态地将组件添加到DOM演示中。


在AngularJS v2.1.1中工作

1
 


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

1
 

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

演示

1
</test>

成分

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

属性绑定

javascript dom外部HTML


下面的代码将帮助您

myval可以用所需的HTML替换

1
 


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

为什么不把模板化的东西放在前端(我建议这样做),或者放在后端(相当内部的IMO)?

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

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

如果你做的对,你将有小的组件与小模板,最重要的是,如果你的代码是IMBA,谁不知道编码语言将能够理解你的模板和你的逻辑!因此,另外,尽可能地减小函数/方法的大小。您最终会发现,与大型函数/方法/类相比,维护、重构、审查和添加功能要容易得多,在前端和后端之间混合模板和逻辑,如果前端需要更灵活(例如,编写Android前端),那么在后端保留尽可能多的逻辑或者切换到不同的前端框架)。

哲学,人:)

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

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