12

I'm using Angular 5.2.10. Suppose we have the following template:

<mat-form-field *appEntityValidate>
    <input
        matInput
        type="text"
        placeholder="Some input">
</mat-form-field>

In EntityValidateDirective, we need to get an instance of MatFormField it's apllied to.

I've tried a solution suggested here, i.e. simply inject MatFormField:

@Directive({
    selector: "[appEntityValidate]"
})
export class EntityValidateDirective {
    constructor(
        private readonly matFormField: MatFormField
    ) {
        const dfg = 0;
    }
}

, but I'm getting an exception from Angular:

No provider for MatFormField!

Here is Stackblitz.

I suspect that this doesn't work because my directive is structural one rather than an attribute one.

So, how to access host component in a structural directive then?

UPDATE: In attempt to address concern raised by @yurzui in comments. Specifically, that MatFormField isn't really a host component in this case, since the above markup gets de-sugarized into something like this:

    <ng-template appEntityValidate>
        <mat-form-field>
            <input matInput type="text" placeholder="Some input">
        </mat-form-field>
    </ng-template> 

Thus, MatFormField becomes a child of the element which EntityValidateDirective is applied to.

To cover this, I've also tried the following:

@Directive({
    selector: "[appEntityValidate]"
})
export class EntityValidateDirective implements AfterContentInit, AfterViewInit {
    @ContentChild(MatFormField) content;
    @ViewChild(MatFormField) view;

    public ngAfterViewInit() {
        const view = this.view;
    }

    public ngAfterContentInit() {
        const content = this.content;
    }
}

But both content and view are undefined in the corresponding lifecycle hook methods.

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129
  • MatFormField is not host component for structural directive but rather part of template – yurzui Apr 17 '18 at 19:09
  • To get this component you first need to create embedded template from your structural directive – yurzui Apr 17 '18 at 19:10
  • @yurzui: Sorry, I'm not sure about both your comments. Could you update/fork the [Stackblitz](https://stackblitz.com/edit/angular-structural-dir-host-issue) to demonstrate how it could be implemented? – Alexander Abakumov Apr 17 '18 at 19:30
  • Look at template https://stackblitz.com/edit/angular-structural-dir-host-issue-czmcxx?file=app/app.component.html Here is how angular sees your directive. So i wonder how you want to MatFormField from host element? – yurzui Apr 17 '18 at 19:35
  • @yurzui: Sure, Angular de-sugars asterisk into `ng-template` making `mat-form-field` its child element. If we'd use this syntax as an illustration, the question should probably be paraphrased as follows: **how to access _child_ component from structural deirective?** Is this what you're saying with your comments? – Alexander Abakumov Apr 17 '18 at 19:45
  • Glad to see you undestood your question:) – yurzui Apr 17 '18 at 19:58
  • @yurzui: Ok, I asked it like this, because I believe this is how further readers would google it and also it sounds more naturally with asterisk syntax. I did know this part. But what I'm still not sure about is how to `create embedded template from your structural directive` and get reference to the child component after that. Would appreciate if you demonstrate this via some code. – Alexander Abakumov Apr 17 '18 at 20:22
  • 2
    **Your problem: Right now, neither DI nor queries allow *structuralDir to communicate with the created view.** https://github.com/angular/angular/issues/15998#issuecomment-294542871 – yurzui Apr 17 '18 at 20:37
  • 2
    Here is a hacky solution https://stackblitz.com/edit/angular-structural-dir-host-issue-75itsr?file=app/entity-validate.directive.ts – yurzui Apr 17 '18 at 20:39
  • @yurzui: Got it, thank you so much for providing the direct answer and the workaround! Although, I don't think I will employ it, since I hoped this approach would be the cleanest way for key tasks in an app I'm designing and I have to make up something else. But apparently, it can be useful for someone else, at least until Angular team implement a fix for this. – Alexander Abakumov Apr 17 '18 at 21:37

0 Answers0