This question already has answers here: Angular4 - No value accessor for form control (4 answers) Closed 28 days ago.
I'm using Angular2-rc5, and I'm currently getting an error on my login page. I'm trying to make a form but the console throws exceptions telling me that it can't find my formcontroll
s even though I create it on init. Any idea why I'm getting this error?
login component
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';
import { LoginService } from './login.service';
import { User } from '../../models/user';
@Component({
selector: 'login',
providers: [LoginService],
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
private loginForm: FormGroup; // our model driven form
private submitted: boolean; // keep track on whether form is submitted
private events: any[] = []; // use later to display form changes
constructor(private fb: FormBuilder, private ls:LoginService){}
ngOnInit(){
this.loginForm = new FormGroup({
email: new FormControl('',[<any>Validators.required]),
password: new FormControl('', [<any>Validators.required, <any>Validators.minLength(6)]),
rememberMe: new FormControl()
});
}
save(model: User, isValid: boolean) {
console.log("Test");
console.log(model, isValid);
}
// Login in user
login(email: any, password: any){
this.ls.login(email, password, false);
}
}
Page.html
<div id="login-page">
<div class="form-wrapper">
<form class="login-form" [formGroup]="loginForm" novalidate (ngSubmit)="save(loginForm.value, loginForm.valid)">
<div >
<div class="input-field col s12 center">
<p class="center login-form-text">Login page</p>
</div>
</div>
<div >
<div class="input-field col s12">
<input id="email" type="email">
<label class="center-align" for="email" formControlName="email">Email</label>
</div>
</div>
<div >
<div class="input-field col s12">
<input id="password" type="password">
<label class="center" for="password" formControlName="password">Password</label>
</div>
</div>
<div >
<div class="input-field col s12 m12 l12 login-text">
<input id="remember-me" type="checkbox" formControlName="rememberMe">
<label for="remember-me">Remember me</label>
</div>
</div>
<div >
<div class="input-field col s12">
<ahref="index.html">Login</a>
</div>
</div>
<div >
<div >
<p><a href="page-register.html">Register Now!</a></p>
</div>
<div >
<p><a href="page-forgot-password.html">Forgot password ?</a></p>
</div>
</div>
</form>
</div>
</div>
Exception
EXCEPTION: Uncaught (in promise): Error: Error in ./LoginComponent class LoginComponent - inline template:13:45 caused by: No value accessor for form control with name: 'email'.....
You are adding the formControlName
to the label and not the input.
You have this:
<div >
<div class="input-field col s12">
<input id="email" type="email">
<label class="center-align" for="email" formControlName="email">Email</label>
</div>
</div>
Try using this:
<div >
<div class="input-field col s12">
<input id="email" type="email" formControlName="email">
<label class="center-align" for="email">Email</label>
</div>
</div>
Update the other input fields as well.
For UnitTest angular 2 with angular material you have to add MatSelectModule module in imports section.
import { MatSelectModule } from '@angular/material';
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CreateUserComponent ],
imports : [ReactiveFormsModule,
MatSelectModule,
MatAutocompleteModule,......
],
providers: [.........]
})
.compileComponents();
}));
For anyone experiencing this in angular 9+
This issue can also be experienced if you do not declare your component or import the module that declares the component.
Lets consider a situation where you intend to use ng-select
but you forget to import it Angular will throw the error 'No value accessor...'
I have reproduced this error in the Below stackblitz demo.
If you get this issue, then either
the formControlName is not located on the value accessor element.
or you're not importing the module for that element.
If you must use the label for the formControl
. Like the Ant Design Checkbox. It may throw this error while running tests. You can use ngDefaultControl
<label nz-checkbox formControlName="isEnabled" ngDefaultControl>
Hello
</label>
<nz-switch nzSize="small" formControlName="mandatory" ngDefaultControl></nz-switch>
In my case I was using ionic, I was trying to unit test ion-input with jasmine karma. I was getting the no value accessor error in the karma browser while running the tests. So I just added the ngDefaultControl
to the ion-input and it solved the problem.
<ion-input class="password" [(ngModel)]="user.password" name="password"
type="password" #pw="ngModel" required ngDefaultControl>
</ion-input>
OR
You need to move your formControlName="controlName"
to the <mat-radio-group>
wrapper instead of binding it to the individual <mat-radio-button>
element (s)
In my case, I used Angular forms with contenteditable
elements like div
and had similar problems before.
I wrote ng-contenteditable module to resolve this problem.
https://i.stack.imgur.com/TW5iP.png
https://i.stack.imgur.com/sasCq.png
You can see formControlName in label , removing this solved my problem
For me I was using primeng dropdown in angular app. The module for dropdown was not imported.
For me, I had the error with ionic date pickers only, I had to import the IonicModule
to my lazy-loaded module
constructor(
private cdr: ChangeDetectorRef,
@Optional()
@Self() public ngControl: NgControl,
) {
if (ngControl) {
ngControl.valueAccessor = this;
}
}
In my case, add this line in custom Control (reuseable) component's constructor
if (ngControl) {
ngControl.valueAccessor = this;
}
In some cases you might missed to add NG_VALUE_ACCESSOR
in reusable component as provider.
@Component({
selector: 'app-reusable',
templateUrl: './reusable.component.html',
styleUrls: ['./reusable.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ReusableComponent),
multi: true,
},
],
})
Success story sharing
@Input formControl
. In one place the formControl was correctly passed to my component in another one the above error occurred. I ended up renaming the formControl input to something distinct. Without this answer I would've never found this :/<mat-form-field>
element and had theformControlName
applied to that (didn't work). Moving it to the contained<mat-select>
element resolved the issue perfectly!