我可以在结构指令中同时做两件事吗?
Can I do two things at once in a structural directive?
我想创建一个结构指令,其行为如下:
<p *myDirective="condition">This is some text</p>
- 如果
condition
是 false
那么 <p>
标签 根本不会 呈现。
- 如果
condition
是 true
,则 <p>
标签会使用额外的 class
属性呈现。
所以,要么没有渲染,要么:
<p class="my-added-class">This is some text</p>
换句话说,它有点像 *ngIf
,但有额外的行为。
我可以找到如何执行 include/exclude 行为的示例(实际上有这样的示例 in the Angular docs). I can also find examples of how to add a class to an element 。
但是,我看不出如何结合这些技术,因为第一种方法操纵 viewContainer
来创建嵌入式 view,而第二种方法使用渲染器操作 元素 .
有办法做到这一点吗?我能以某种方式创建嵌入式视图然后操作它创建的元素吗?或者我可以操纵模板来更改视图的呈现方式吗?
[注意:@HostBinding
不适用于结构指令,因此这不是一个选项]
当 DOM 满足传递给它的表达式(在 setter 内)时,我会考虑在 DOM 上添加 class。您可以在指令中获取 ElementRef
依赖项并向其附加一个 class
它是真实的。
@Input() set myDirective(condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.elementRef.nativeElement.nextElementSibling.classList.add('my-added-class'); // renderer API can be used here
// as Alex and Yurzui suggested
// const view = this.viewContainer.createEmbeddedView(this.templateRef);
// view.rootNodes[0].classList.add('some-class')
} else if (condition) {
this.viewContainer.clear();
}
}
另一种方式
随便玩玩:)
使用 Renderer2 是普遍安全的
import {
Directive,
Renderer2,
TemplateRef,
ViewContainerRef,
ElementRef,
Input, OnInit } from '@angular/core';
@Directive({
selector: '[appMy]'
})
export class MyDirective implements OnInit{
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private renderer: Renderer2) { }
@Input() set appMy(condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
ngOnInit() {
const elementRef = this.viewContainer.get(0).rootNodes[0] as ElementRef;
this.renderer.addClass(elementRef, 'myclass');
}
}
遵循@Pankaj 的方式,但使用渲染器
@Input() set appMy(condition: boolean) {
if (condition) {
const view = this.viewContainer.createEmbeddedView(this.templateRef);
this.renderer.addClass(view.rootNodes[0], 'myclass');
} else {
this.viewContainer.clear();
}
}
我想创建一个结构指令,其行为如下:
<p *myDirective="condition">This is some text</p>
- 如果
condition
是false
那么<p>
标签 根本不会 呈现。 - 如果
condition
是true
,则<p>
标签会使用额外的class
属性呈现。
所以,要么没有渲染,要么:
<p class="my-added-class">This is some text</p>
换句话说,它有点像 *ngIf
,但有额外的行为。
我可以找到如何执行 include/exclude 行为的示例(实际上有这样的示例 in the Angular docs). I can also find examples of how to add a class to an element
但是,我看不出如何结合这些技术,因为第一种方法操纵 viewContainer
来创建嵌入式 view,而第二种方法使用渲染器操作 元素 .
有办法做到这一点吗?我能以某种方式创建嵌入式视图然后操作它创建的元素吗?或者我可以操纵模板来更改视图的呈现方式吗?
[注意:@HostBinding
不适用于结构指令,因此这不是一个选项]
当 DOM 满足传递给它的表达式(在 setter 内)时,我会考虑在 DOM 上添加 class。您可以在指令中获取 ElementRef
依赖项并向其附加一个 class
它是真实的。
@Input() set myDirective(condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.elementRef.nativeElement.nextElementSibling.classList.add('my-added-class'); // renderer API can be used here
// as Alex and Yurzui suggested
// const view = this.viewContainer.createEmbeddedView(this.templateRef);
// view.rootNodes[0].classList.add('some-class')
} else if (condition) {
this.viewContainer.clear();
}
}
另一种方式
随便玩玩:)
使用 Renderer2 是普遍安全的
import {
Directive,
Renderer2,
TemplateRef,
ViewContainerRef,
ElementRef,
Input, OnInit } from '@angular/core';
@Directive({
selector: '[appMy]'
})
export class MyDirective implements OnInit{
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef,
private renderer: Renderer2) { }
@Input() set appMy(condition: boolean) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
} else {
this.viewContainer.clear();
}
}
ngOnInit() {
const elementRef = this.viewContainer.get(0).rootNodes[0] as ElementRef;
this.renderer.addClass(elementRef, 'myclass');
}
}
遵循@Pankaj 的方式,但使用渲染器
@Input() set appMy(condition: boolean) {
if (condition) {
const view = this.viewContainer.createEmbeddedView(this.templateRef);
this.renderer.addClass(view.rootNodes[0], 'myclass');
} else {
this.viewContainer.clear();
}
}