Angular 2 相当于 ng-bind-html、$sce.trustAsHTML() 和 $compile?
Angular 2 equivalent of ng-bind-html, $sce.trustAsHTML(), and $compile?
在Angular1.x中,我们可以通过使用HTML标签ng-bind-html
,结合[=40]实时插入HTML =] 调用 $sce.trustAsHTML()
。这让我们完成了 80% 的事情,但在使用 Angular 标签时不起作用,例如如果您插入了使用 ng-repeat
或自定义指令的 HTML。
为了让它工作,我们可以使用 custom directive that called $compile.
Angular2 中所有这些的等价物是什么?我们可以使用 [inner-html]
进行绑定,但这只适用于非常简单的 HTML 标签,例如 <b>
。它不会将自定义 angular 2 指令转换为功能性 HTML 元素。 (很像没有 $compile
步骤的 Angular 1.x。) Angular 2 的 $compile
是什么?
在 Angular2 中,您应该使用 DynamicComponentLoader 在页面上插入一些 "compiled content"。例如,如果你想编译下一个 html:
<div>
<p>Common HTML tag</p>
<angular2-component>Some angular2 component</angular2-component>
</div>
然后您需要使用此 html 作为模板创建组件(我们称之为 CompiledComponent
)并使用 DynamicComponentLoader
将此组件插入页面。
@Component({
selector: 'compiled-component'
})
@View({
directives: [Angular2Component],
template: `
<div>
<p>Common HTML tag</p>
<angular2-component>Angular 2 component</angular2-component>
</div>
`
})
class CompiledComponent {
}
@Component({
selector: 'app'
})
@View({
template: `
<h2>Before container</h2>
<div #container></div>
<h2>After conainer</h2>
`
})
class App {
constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
}
}
查看 this plunker
UPD 您可以在 loader.loadIntoLocation()
调用之前动态创建组件:
// ... annotations
class App {
constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
// template generation
const generatedTemplate = `<b>${Math.random()}</b>`;
@Component({ selector: 'compiled-component' })
@View({ template: generatedTemplate })
class CompiledComponent {};
loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
}
}
我个人不喜欢它,对我来说它看起来像是一个肮脏的黑客。但是这里是 the plunker
PS 请注意,此时 angular2 正在积极开发中。所以情况可以随时改变。
在阅读了很多内容之后,并且即将开启一个新主题之后,我决定在这里回答,只是为了帮助其他人。正如我所见,最新版本的 Angular 2 有一些变化。(当前为 Beta9)
我会尝试分享我的代码,以避免我遇到同样的挫败感...
首先,在我们的index.html
像往常一样,我们应该有这样的东西:
<html>
****
<body>
<my-app>Loading...</my-app>
</body>
</html>
AppComponent(使用内部HTML)
有了这个 属性 你将能够渲染基本的 HTML,但是你将无法做类似于 Angular 1.x 的事情 $通过范围编译:
import {Component} from 'angular2/core';
@Component({
selector: 'my-app',
template: `
<h1>Hello my Interpolated: {{title}}!</h1>
<h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
<div [innerHTML]="htmlExample"></div>
`,
})
export class AppComponent {
public title = 'Angular 2 app';
public htmlExample = ' <div>' +
'<span [textContent]="\'Hello my Property bound: \'+title"></span>' +
'<span>Hello my Interpolated: {{title}}</span>' +
'</div>'
}
这将呈现以下内容:
Hello my Interpolated: Angular 2 app!
Hello my Property bound: Angular 2 app!
Hello my Interpolated: {{title}}
AppComponent 使用 DynamicComponentLoader
文档中有一个小错误,记录在 中。因此,如果我们牢记这一点,我的代码现在应该如下所示:
import {DynamicComponentLoader, Injector, Component, ElementRef, OnInit} from "angular2/core";
@Component({
selector: 'child-component',
template: `
<div>
<h2 [textContent]="'Hello my Property bound: '+title"></h2>
<h2>Hello my Interpolated: {{title}}</h2>
</div>
`
})
class ChildComponent {
title = 'ChildComponent title';
}
@Component({
selector: 'my-app',
template: `
<h1>Hello my Interpolated: {{title}}!</h1>
<h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
<div #child></div>
<h1>End of parent: {{endTitle}}</h1>
`,
})
export class AppComponent implements OnInit{
public title = 'Angular 2 app';
public endTitle= 'Bye bye!';
constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {
// dynamicComponentLoader.loadIntoLocation(ChildComponent, elementRef, 'child');
}
ngOnInit():any {
this.dynamicComponentLoader.loadIntoLocation(ChildComponent, this.elementRef, 'child');
}
}
这将呈现以下内容:
Hello my Interpolated: Angular 2 app!
Hello my Property bound: Angular 2 app!
Hello my Property bound: ChildComponent title
Hello my Interpolated: ChildComponent title
End of parent: Bye bye!
Angular 提供 DynamicComponentLoader
class 用于动态加载 html。 DynamicComponentLoader
有插入组件的方法。 loadIntoLocation
是其中之一用于插入组件。
paper.component.ts
import {Component,DynamicComponentLoader,ElementRef,Inject,OnInit} from 'angular2/core';
import { BulletinComponent } from './bulletin.component';
@Component({
selector: 'paper',
templateUrl: 'app/views/paper.html'
}
})
export class PaperComponent {
constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {
}
ngOnInit(){
this.dynamicComponentLoader.loadIntoLocation(BulletinComponent, this.elementRef,'child');
}
}
bulletin.component.ts
import {Component} from 'angular2/core';
@Component({
selector: 'bulletin',
templateUrl: 'app/views/bulletin.html'
}
})
export class BulletinComponent {}
paper.html
<div>
<div #child></div>
</div>
您需要注意的几件事:
- 不要在 class 的构造函数中调用
loadIntoLocation
。调用组件构造函数时尚未创建组件视图。你会得到错误 -
Error during instantiation of AppComponent!. There is no component
directive at element [object Object]
- 将 anchorName #child 放在 html 中,否则会出错。
Could not find variable child
DynamicComponentLoader 已弃用,您可以改用 ComponentResolver
您可以使用此指令,如果需要额外的数据操作,请添加管道。它还允许延迟加载,你不需要它,但值得一提。
指令(我找到了这段代码并做了一些修改,你也可以这样做以使其符合你的口味或按原样使用):
import { Component, Directive, ComponentFactory, ComponentMetadata, ComponentResolver, Input, ReflectiveInjector, ViewContainerRef } from '@angular/core';
declare var $:any;
export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent {};
const decoratedCmp = Component(metadata)(cmpClass);
return resolver.resolveComponent(decoratedCmp);
}
@Directive({
selector: 'dynamic-html-outlet',
})
export class DynamicHTMLOutlet {
@Input() htmlPath: string;
@Input() cssPath: string;
constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
}
ngOnChanges() {
if (!this.htmlPath) return;
$('dynamic-html') && $('dynamic-html').remove();
const metadata = new ComponentMetadata({
selector: 'dynamic-html',
templateUrl: this.htmlPath +'.html',
styleUrls: [this.cssPath]
});
createComponentFactory(this.resolver, metadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.vcRef.createComponent(factory, 0, injector, []);
});
}
}
使用示例:
import { Component, OnInit } from '@angular/core';
import { DynamicHTMLOutlet } from './../../directives/dynamic-html-outlet/dynamicHtmlOutlet.directive';
@Component({
selector: 'lib-home',
templateUrl: './app/content/home/home.component.html',
directives: [DynamicHTMLOutlet]
})
export class HomeComponent implements OnInit{
html: string;
css: string;
constructor() {}
ngOnInit(){
this.html = './app/content/home/home.someTemplate.html';
this.css = './app/content/home/home.component.css';
}
}
home.component.html:
<dynamic-html-outlet [htmlPath]="html" [cssPath]="css"></dynamic-html-outlet>
看看这个模块https://www.npmjs.com/package/ngx-dynamic-template
经过长时间的研究,只有这件事对我有帮助。其余解决方案似乎已过时。
我想你所要做的就是用 [innerHTML]="yourcomponentscopevar"
设置你想要编译的元素 html
在Angular1.x中,我们可以通过使用HTML标签ng-bind-html
,结合[=40]实时插入HTML =] 调用 $sce.trustAsHTML()
。这让我们完成了 80% 的事情,但在使用 Angular 标签时不起作用,例如如果您插入了使用 ng-repeat
或自定义指令的 HTML。
为了让它工作,我们可以使用 custom directive that called $compile.
Angular2 中所有这些的等价物是什么?我们可以使用 [inner-html]
进行绑定,但这只适用于非常简单的 HTML 标签,例如 <b>
。它不会将自定义 angular 2 指令转换为功能性 HTML 元素。 (很像没有 $compile
步骤的 Angular 1.x。) Angular 2 的 $compile
是什么?
在 Angular2 中,您应该使用 DynamicComponentLoader 在页面上插入一些 "compiled content"。例如,如果你想编译下一个 html:
<div>
<p>Common HTML tag</p>
<angular2-component>Some angular2 component</angular2-component>
</div>
然后您需要使用此 html 作为模板创建组件(我们称之为 CompiledComponent
)并使用 DynamicComponentLoader
将此组件插入页面。
@Component({
selector: 'compiled-component'
})
@View({
directives: [Angular2Component],
template: `
<div>
<p>Common HTML tag</p>
<angular2-component>Angular 2 component</angular2-component>
</div>
`
})
class CompiledComponent {
}
@Component({
selector: 'app'
})
@View({
template: `
<h2>Before container</h2>
<div #container></div>
<h2>After conainer</h2>
`
})
class App {
constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
}
}
查看 this plunker
UPD 您可以在 loader.loadIntoLocation()
调用之前动态创建组件:
// ... annotations
class App {
constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
// template generation
const generatedTemplate = `<b>${Math.random()}</b>`;
@Component({ selector: 'compiled-component' })
@View({ template: generatedTemplate })
class CompiledComponent {};
loader.loadIntoLocation(CompiledComponent, elementRef, 'container');
}
}
我个人不喜欢它,对我来说它看起来像是一个肮脏的黑客。但是这里是 the plunker
PS 请注意,此时 angular2 正在积极开发中。所以情况可以随时改变。
在阅读了很多内容之后,并且即将开启一个新主题之后,我决定在这里回答,只是为了帮助其他人。正如我所见,最新版本的 Angular 2 有一些变化。(当前为 Beta9)
我会尝试分享我的代码,以避免我遇到同样的挫败感...
首先,在我们的index.html
像往常一样,我们应该有这样的东西:
<html>
****
<body>
<my-app>Loading...</my-app>
</body>
</html>
AppComponent(使用内部HTML)
有了这个 属性 你将能够渲染基本的 HTML,但是你将无法做类似于 Angular 1.x 的事情 $通过范围编译:
import {Component} from 'angular2/core';
@Component({
selector: 'my-app',
template: `
<h1>Hello my Interpolated: {{title}}!</h1>
<h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
<div [innerHTML]="htmlExample"></div>
`,
})
export class AppComponent {
public title = 'Angular 2 app';
public htmlExample = ' <div>' +
'<span [textContent]="\'Hello my Property bound: \'+title"></span>' +
'<span>Hello my Interpolated: {{title}}</span>' +
'</div>'
}
这将呈现以下内容:
Hello my Interpolated: Angular 2 app!
Hello my Property bound: Angular 2 app!
Hello my Interpolated: {{title}}
AppComponent 使用 DynamicComponentLoader
文档中有一个小错误,记录在
import {DynamicComponentLoader, Injector, Component, ElementRef, OnInit} from "angular2/core";
@Component({
selector: 'child-component',
template: `
<div>
<h2 [textContent]="'Hello my Property bound: '+title"></h2>
<h2>Hello my Interpolated: {{title}}</h2>
</div>
`
})
class ChildComponent {
title = 'ChildComponent title';
}
@Component({
selector: 'my-app',
template: `
<h1>Hello my Interpolated: {{title}}!</h1>
<h1 [textContent]="'Hello my Property bound: '+title+'!'"></h1>
<div #child></div>
<h1>End of parent: {{endTitle}}</h1>
`,
})
export class AppComponent implements OnInit{
public title = 'Angular 2 app';
public endTitle= 'Bye bye!';
constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {
// dynamicComponentLoader.loadIntoLocation(ChildComponent, elementRef, 'child');
}
ngOnInit():any {
this.dynamicComponentLoader.loadIntoLocation(ChildComponent, this.elementRef, 'child');
}
}
这将呈现以下内容:
Hello my Interpolated: Angular 2 app!
Hello my Property bound: Angular 2 app!
Hello my Property bound: ChildComponent title
Hello my Interpolated: ChildComponent title
End of parent: Bye bye!
Angular 提供 DynamicComponentLoader
class 用于动态加载 html。 DynamicComponentLoader
有插入组件的方法。 loadIntoLocation
是其中之一用于插入组件。
paper.component.ts
import {Component,DynamicComponentLoader,ElementRef,Inject,OnInit} from 'angular2/core';
import { BulletinComponent } from './bulletin.component';
@Component({
selector: 'paper',
templateUrl: 'app/views/paper.html'
}
})
export class PaperComponent {
constructor(private dynamicComponentLoader:DynamicComponentLoader, private elementRef: ElementRef) {
}
ngOnInit(){
this.dynamicComponentLoader.loadIntoLocation(BulletinComponent, this.elementRef,'child');
}
}
bulletin.component.ts
import {Component} from 'angular2/core';
@Component({
selector: 'bulletin',
templateUrl: 'app/views/bulletin.html'
}
})
export class BulletinComponent {}
paper.html
<div>
<div #child></div>
</div>
您需要注意的几件事:
- 不要在 class 的构造函数中调用
loadIntoLocation
。调用组件构造函数时尚未创建组件视图。你会得到错误 -
Error during instantiation of AppComponent!. There is no component directive at element [object Object]
- 将 anchorName #child 放在 html 中,否则会出错。
Could not find variable child
DynamicComponentLoader 已弃用,您可以改用 ComponentResolver
您可以使用此指令,如果需要额外的数据操作,请添加管道。它还允许延迟加载,你不需要它,但值得一提。
指令(我找到了这段代码并做了一些修改,你也可以这样做以使其符合你的口味或按原样使用):
import { Component, Directive, ComponentFactory, ComponentMetadata, ComponentResolver, Input, ReflectiveInjector, ViewContainerRef } from '@angular/core';
declare var $:any;
export function createComponentFactory(resolver: ComponentResolver, metadata: ComponentMetadata): Promise<ComponentFactory<any>> {
const cmpClass = class DynamicComponent {};
const decoratedCmp = Component(metadata)(cmpClass);
return resolver.resolveComponent(decoratedCmp);
}
@Directive({
selector: 'dynamic-html-outlet',
})
export class DynamicHTMLOutlet {
@Input() htmlPath: string;
@Input() cssPath: string;
constructor(private vcRef: ViewContainerRef, private resolver: ComponentResolver) {
}
ngOnChanges() {
if (!this.htmlPath) return;
$('dynamic-html') && $('dynamic-html').remove();
const metadata = new ComponentMetadata({
selector: 'dynamic-html',
templateUrl: this.htmlPath +'.html',
styleUrls: [this.cssPath]
});
createComponentFactory(this.resolver, metadata)
.then(factory => {
const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
this.vcRef.createComponent(factory, 0, injector, []);
});
}
}
使用示例:
import { Component, OnInit } from '@angular/core';
import { DynamicHTMLOutlet } from './../../directives/dynamic-html-outlet/dynamicHtmlOutlet.directive';
@Component({
selector: 'lib-home',
templateUrl: './app/content/home/home.component.html',
directives: [DynamicHTMLOutlet]
})
export class HomeComponent implements OnInit{
html: string;
css: string;
constructor() {}
ngOnInit(){
this.html = './app/content/home/home.someTemplate.html';
this.css = './app/content/home/home.component.css';
}
}
home.component.html:
<dynamic-html-outlet [htmlPath]="html" [cssPath]="css"></dynamic-html-outlet>
看看这个模块https://www.npmjs.com/package/ngx-dynamic-template
经过长时间的研究,只有这件事对我有帮助。其余解决方案似乎已过时。
我想你所要做的就是用 [innerHTML]="yourcomponentscopevar"
设置你想要编译的元素 html