Angular 如何从指令访问主机组件?
假设我有以下标记:Angular 如何从指令访问主机组件?,angular,angular-directive,Angular,Angular Directive,假设我有以下标记: <my-comp myDirective></my-comp> 是否有任何方法可以从指令访问组件实例 更具体地说,我希望能够从MyDirective访问MyComponent的属性和方法,理想情况下无需向上面的HTML添加任何内容您只需注入它即可 class MyDirective { constructor(private host:MyComponent) {} 一个严重的限制是,您需要提前知道组件的类型 另见 当您事先不知道类型时,它
<my-comp myDirective></my-comp>
是否有任何方法可以从指令访问组件实例
更具体地说,我希望能够从MyDirective
访问MyComponent
的属性和方法,理想情况下无需向上面的HTML添加任何内容您只需注入它即可
class MyDirective {
constructor(private host:MyComponent) {}
一个严重的限制是,您需要提前知道组件的类型
另见当您事先不知道类型时,它还提供了一些解决方法。您的指令可以是可应用于任何组件的通用指令。所以,在这种情况下,在构造函数中注入组件是不可能的,所以这里有另一种方法来做同样的事情 在构造函数中插入
ViewContainerRef
constructor(private _viewContainerRef: ViewContainerRef) { }
然后使用
let hostComponent = this._viewContainerRef["_data"].componentView.component;
这是从github问题中提取出来的,它就像一个符咒。缺点是需要事先知道组件,但在您的情况下,您仍然需要知道正在使用的方法
import { Host, Self, Optional } from '@angular/core';
constructor(
@Host() @Self() @Optional() public hostCheckboxComponent : MdlCheckboxComponent
,@Host() @Self() @Optional() public hostSliderComponent : MdlSliderComponent){
if(this.hostCheckboxComponent) {
console.log("host is a checkbox");
} else if(this.hostSliderComponent) {
console.log("host is a slider");
}
}
学分:
构造函数(专用vcRef:ViewContainerRef){
让parentComponent=(this.vcRef)。\u view.context;
}
如果要在自定义组件上使用attribute指令,可以将这些组件从抽象类和“forwardRef”抽象类类型扩展到组件类型。通过这种方式,您可以在抽象类(在您的指令中)上进行angular的DI选择
抽象类:
export abstract class MyReference {
// can be empty if you only want to use it as a reference for DI
}
自定义组件:
@Component({
// ...
providers: [
{provide: MyReference, useExisting: forwardRef(() => MyCustomComponent)}
],
})
export class MyCustomComponent extends MyReference implements OnInit {
// ...
}
指令:
@Directive({
selector: '[appMyDirective]'
})
export class CustomDirective{
constructor(private host:MyReference) {
console.log(this.host);
// no accessing private properties of viewContainerRef to see here... :-)
}
}
这样,您就可以在扩展抽象类的任何组件上使用该指令
这当然只适用于您自己的组件。我喜欢这样,它适用于Angular 9
export class FromItemComponentBase {
constructor(private hostElement: ElementRef) {
hostElement.nativeElement.__component=this;
}
}
可以使用ViewContainerRef访问主机组件
constructor(private el: ViewContainerRef) {}
ngOnInit() {
const _component = this.el && this.el.injector && this.el.injector.get(MyComponent);
}
参考:使指令通用的一个可能的解决方法是将组件的模板ref作为@Input传递给指令。这增加了一点额外的html,但它比我尝试过的许多其他黑客更有效
@Directive({selector: '[myDirective]'})
export class MyDirective implements OnInit {
@Input() componentRef: any;
@Input() propName: string;
ngOnInit(){
if (this.componentRef != null) {
// Access component properties
this.componentRef[this.propName];
}
}
}
视图中的用法:
属性,以获取对指令实例的引用
谢谢你,甘特,这很有效。理想情况下,我需要一个适用于任何组件的通用解决方案。事实上,对于我在这里试图做的事情,您可能有一个建议:许多人都要求一个通用的解决方案(正如您在链接的问题中所看到的),但目前没有简单的解决方案。@GünterZöchbauer我想我们可以使用一个接口,例如构造函数(私有主机:HostedComponentInterface){
并要求指令的用户实现该接口??TypeScript接口在运行时不存在,因此DI不支持该接口。@Emobe我没有遇到过很多找不到解决方案的情况。这是最困难的一次。对其他人来说,通常有很好的解决办法。大多数设计决策都是为了提高效率,我认为这是值得的。虽然这段代码片段可以解决这个问题,但它确实有助于提高文章的质量。请记住,您将在将来为读者回答这个问题,而这些人可能不知道您的代码建议的原因。\u view.context
意味着\u view
应该是私有的,因此您似乎是以非标准的方式这样做的,就像对以后遇到此问题的人发出的一声喊叫一样。引用:从Angular 9.0.0-next.3开始,此解决方案不再有效。你知道他们现在可能把它藏在哪里了吗?@Fredrik_Macrobond.last(this.viewContainerRef['''u hostView'][0]。\uuuu ngContext\uu)有人找到了一个适合常春藤的解决方案吗?Angular10A含有Angular 12:(this.viewContainerRef如有)的非常脏的溶液。\u hostLView[8]
。8引用中的上下文(内联)以谨慎使用。这看起来是我的完美解决方案,它有任何缺点吗?这就是我需要引用DirectiveMember中的任何组件以使抽象类可注入的原因,否则您的指令中会出现错误。例如,将@Injectable({providedIn:'root'})
作为属性添加到摘要中class@SlavaFominII请仔细查看,没有使用私有API。请保持更正,抱歉。组件的外观把我弄糊涂了。
@Directive({selector: 'input-error,input-password,input-text'})
export class FormInputDirective {
component:FromItemComponentBase;
constructor(private hostElement: ElementRef) {
this.component=hostElement.nativeElement.__component;
}
}
constructor(private el: ViewContainerRef) {}
ngOnInit() {
const _component = this.el && this.el.injector && this.el.injector.get(MyComponent);
}
@Directive({selector: '[myDirective]'})
export class MyDirective implements OnInit {
@Input() componentRef: any;
@Input() propName: string;
ngOnInit(){
if (this.componentRef != null) {
// Access component properties
this.componentRef[this.propName];
}
}
}