0

I've being trying to create custom elements with angular elements and for form inputs I've being trying to use angular's ControlValueAccessor for that as discussed in this article by Eliran Eliassy.

But when I follow the guide, and completed the code - I ran into this problem. No provider for NgControl. I have already imported FormsModule and ReactiveFormsModule to app.module.ts file which is the remedy for this error (as normal). But it haven't fixed this time.

StackBlitz Example

What will be the problem? I attached the stackbliz above for your reference.

Edric
  • 24,639
  • 13
  • 81
  • 91
Kavinda Jayakody
  • 705
  • 1
  • 13
  • 25

5 Answers5

3

Thanks for posting here for more people get benefited from it.

You did 2 mistakes there:

  1. When you injecting the NgControl, you don't have to provide the NG_VALUE_ACCESSOR token. the reason is NgControl is already providing the NG_VALUE_ACCESSOR token, and if you do it as well, you will run into a circular dependency issue.

  2. Because your TestComponent is an entry component, you also have to add the @Optional() decorator before your NgControl injection. The reason is when you declaring a component in the entry component, angular compiles it factory even that it's not on the template, and because it's not part of any form and doesn't have any From directive on it, you will get this error of No provider for NgControl

Hope that helps!

Eliran Eliassy
  • 1,590
  • 12
  • 25
  • Hello @Eliran, i tried them actually. Check the updated [StackBlitz](https://stackblitz.com/edit/angular-dhp2f9) with the recommendations you mentioned. Now the previous error is gone, but introduced these two new ones. ``` Error: No value accessor for form control with name: 'email' ``` And ``` TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function. ``` You can recreate them in the updated StackBlitz. Thank you :) – Kavinda Jayakody Aug 25 '19 at 12:01
  • Plus, when i'm trying your solution in my local environment - it gives the error -> **ERROR TypeError: Cannot set property 'valueAccessor' of null** and **ERROR Error: Uncaught (in promise): Error: No value accessor for form control with name: 'email'** – Kavinda Jayakody Aug 26 '19 at 09:19
  • Again, because not always your DI will get `NgControl`, of course, you can just add `if` statement to check wheater you got it or not before you set the `valueAccessor` prop. – Eliran Eliassy Aug 27 '19 at 05:23
  • I tried that even @Eliran :/. That leads to **ERROR TypeError: Cannot read property 'control' of null** which is actually the expected behaviour. So how can we rightfully inject the DI for NgControl if the one coming from the DI is null? – Kavinda Jayakody Aug 27 '19 at 05:52
  • 1
    I see...and it makes sense if we thinking about it again. So, I think that for that case, maybe getting the NgControl from the DI is not the best option. Need to find another way of doing it. – Eliran Eliassy Aug 27 '19 at 12:44
  • Yeah it seems so. I tried with the Injector (like injector.get(NgControl)) that also leads to static injection error. Have you got any idea on how the dependency must injected? – Kavinda Jayakody Aug 27 '19 at 13:06
  • Hello @Eliran. According to this comment (https://github.com/angular/angular/issues/31351#issuecomment-508576239) we can implement the control valve accessor. How can we do that? You got any idea? – Kavinda Jayakody Aug 28 '19 at 19:24
  • @KavindaJayakody Hey, I fell in the same issue - have you gotten any solution in you case? – Bruno Bruzzano Jun 23 '20 at 08:04
  • @BrunoBruzzano i did found a solution, but not an elegant one i must say. Anyway it works and my custom element UI Kit is live in production now without problems. See this answer https://stackoverflow.com/a/57706681/6686446. I say again, not the elegant way – Kavinda Jayakody Jun 23 '20 at 14:48
1

Something is wrong with your AppModule and DoBootstrap implementation. If you remove it and additionally remove your component from entryComponents in appModule and change how it is used at the app-component.html everything seems to work fine.

app.module.ts

@NgModule({
  imports: [BrowserModule, FormsModule, ReactiveFormsModule],
  declarations: [AppComponent, HelloComponent, TestInputComponent],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule  {
  constructor(private injector: Injector) {

  }
}

app.component.html

<form class="form-signin" (ngSubmit)="onSubmit(f.value)" #f="ngForm" >
  <app-test-input [placeholder]="'Email'"
                          [isRequired]="true"
                          [errorMsg]="'Please enter your name'"
                          [label] = "'User Email'"
                          [pattern]="'[A-Za-z0-9._%-]+@[A-Za-z0-9._%-]+\\.[a-z]{2,3}'"
                          ngModel name="email"></app-test-input>

  <button class="btn btn-lg btn-primary btn-block" [disabled]="!f.valid" type="submit">Sign in</button>
</form>
Stefan
  • 1,431
  • 2
  • 17
  • 33
  • No :/. That didn't fixed the issue. On the other hand, we shouldn't add NG_VALUE_ACCESSOR provider since NgControl already importing that (which may lead to cyclic dependency) – Kavinda Jayakody Aug 23 '19 at 12:32
  • 1
    I have to use doBootstrap for creating the custom element from angular elements anyhow :/ – Kavinda Jayakody Aug 23 '19 at 13:11
  • Even in that example they have placed the custom-element-comp (testcomponent) in the entry components list (not in the declarations array). What to do about that? – Kavinda Jayakody Aug 24 '19 at 03:58
1

Found the solution.

Fixed the error by adding the ngDefaultControl as a directive in the custom element and implementing the part of the ControlValueAccessor manually.

Here is an example of implementation (Don't mind the validation part, not finished yet) StackBlitz

Please follow these issues for more information.

Kavinda Jayakody
  • 705
  • 1
  • 13
  • 25
0

remove this line from your app.module.ts

entryComponents: [TestInputComponent]

also u have removed DoBootstrap implementation from app.module.ts and replace ust-input with app-test-input and it will works.also remove

providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: TestInputComponent,
      multi: true
    }]

because it's create cyclic dependency.

0

For everyone else who get this Error, in my case the problem was a missing formControlName property and a missing formGroup as a parent. If you use custom form controls in your project as well, ensure all references - formControlName's and [formGroup]="myFormGroup" - are set properly.

svenson95
  • 21
  • 2