question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Use FormControlDirective

See original GitHub issue

It’s currently not possible to apply FormControlDirective to a dynamic component. It fails during the createDirective with the following error:

ERROR Error: StaticInjectorError(AppModule)[Array]: 
  StaticInjectorError(Platform: core)[Array]: 
    NullInjectorError: No provider for Array!
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:3228)
    at resolveToken (core.js:3473)
    at tryResolveToken (core.js:3417)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:3314)
    at resolveToken (core.js:3473)
    at tryResolveToken (core.js:3417)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:3314)
    at resolveNgModuleDep (core.js:19784)
    at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:20473)
    at resolveNgModuleDep (core.js:19784)

Its seems it gets tricked by the peculiar directive constructor and want to resolve to the arrays. I’m not familiar with the reflect method which is at play but it seems it ignore the Injection Tokens in the metadata sur as @Inject(NG_VALIDATORS) see https://github.com/angular/angular/blob/cabf1c71059140a2f7855790a9e8ea79b6745f3a/packages/forms/src/directives/reactive_directives/form_control_directive.ts#L166

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:14 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
gundcommented, May 13, 2019

Hey, sorry I did not look into this issue for quite some time.

Again as I said before I do not see how we can resolve this problem as it is recursive - you need to have component created in order to resolve directives, but you also need to have directives to create component…

We have to analyse dependencies of component and directives before their creation in order to prioritise the order of instantiation - and it looks a bit complex to me right now.

Even if you look at the latest code snip from @sandorfr you can see the problem - he first creates the component, and then creates a directive manually from the injector of the new component, but if component will have to access that directive - it will fail as it was not provided…

1reaction
sandorfrcommented, Dec 14, 2018

Sorry by advance if I come out strong, but I’m really trying to help and also understand what has to be done to make it work. If I can come up with a good solution. I’d like to submit a PR.

The problem is that component will already exist by the time dynamic directive is gonna be created.

I don’t get why it’s a problem. But yes the component is instantiated first

And what it means that component’s injector was already created without that directive being available in it.

It’s the normal behavior of directive, they are not created in the component but on top of it and “attached”

So without dynamic injector there is nothing we can do about it. I don’t get the need for a dynamic injector here.

ViewContainerRef.createComponent returns a ComponentRef<MyComponent> which include a child injector. This injector has the reference to MyComponent, but also any provider defined at the component level (such as NG_VALUE_ACCESSOR which is the corner stone of the FormControlDirective).

This child injector can then be used to instantiate the the Directive and things like you mentioned @Host() myComponent: MyComponent will be honored.

I’ve experimented a little bit more outside of the library to get a better understanding without the complexity of everything else it provides and the following works.

initializeComponent() {
    const factory = this.resolver.resolveComponentFactory(DynamiteComponent);
    const ref = this.vc.createComponent(factory);

    const instance = ref.injector.get(DynamiteComponent, InjectFlags.Optional);
    console.log("component", instance);
    const valueAccessor = ref.injector.get(
      NG_VALUE_ACCESSOR,
      InjectFlags.Optional
    );
    console.log("valueAccessor", valueAccessor);

    const flags: any = InjectFlags.Optional | InjectFlags.Self;
    const validators = ref.injector.get(NG_VALIDATORS, null, flags);
    console.log("validators", validators);

    console.log("flags", flags);

    const formControl = new FormControlDirective(
      ref.injector.get(NG_VALIDATORS, null, flags) as any,
      ref.injector.get(NG_ASYNC_VALIDATORS, null, flags) as any,
      ref.injector.get(NG_VALUE_ACCESSOR, null, flags) as any,
      null
    );

    console.log("formControl", formControl);

    formControl.form = this.form;

    formControl.ngOnChanges({
      form: new SimpleChange(undefined, formControl.form, true)
    });

    this.component = ref;

  }

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

FormControlDirective - Angular
Returns an array that represents the path from the top-level form to this control. Each index is the string name of the control...
Read more >
Angular forms FormControlDirective - GeeksforGeeks
Create the Angular app to be used; In app.component.ts make an object that contains a value for the input. In app.component.html use ......
Read more >
Attempting to extend FormControlDirective to implement my ...
Debugging it shows that there are no valueAccessor injected to the constructor (unlike when using the base FormControlDirective class ...
Read more >
angular/form_control_directive.ts at main - GitHub
Static property used to track whether any ngModel warnings have been sent across. * all instances of FormControlDirective. Used to support warning config...
Read more >
FormControlDirective - Angular
Write-only. Triggers a warning that this input should not be used with reactive forms. @Input('ngModel') model: any.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found