mat-form-field must contain a MatFormFieldControl
AngularTypescriptAngular Material2Angular Problem Overview
We are trying to build our own form-field-Components at our Company. We are trying to wrap material design's Components like this:
field:
<mat-form-field>
<ng-content></ng-content>
<mat-hint align="start"><strong>{{hint}}</strong> </mat-hint>
<mat-hint align="end">{{message.value.length}} / 256</mat-hint>
<mat-error>This field is required</mat-error>
</mat-form-field>
textbox:
<field hint="hint">
<input matInput
[placeholder]="placeholder"
[value]="value"
(change)="onChange($event)"
(keydown)="onKeydown($event)"
(keyup)="onKeyup($event)"
(keypress)="onKeypress($event)">
</field>
Usage:
<textbox value="test" hint="my hint"></textbox>
This results in approximately this:
<textbox placeholder="Personnummer/samordningsnummer" value="" ng-reflect-placeholder="Personnummer/samordningsnummer">
<field>
<mat-form-field class="mat-input-container mat-form-field>
<div class="mat-input-wrapper mat-form-field-wrapper">
<div class="mat-input-flex mat-form-field-flex">
<div class="mat-input-infix mat-form-field-infix">
<input _ngcontent-c4="" class="mat-input-element mat-form-field-autofill-control" matinput="" ng-reflect-placeholder="Personnummer/samordningsnummer" ng-reflect-value="" id="mat-input-2" placeholder="Personnummer/samordningsnummer" aria-invalid="false">
<span class="mat-input-placeholder-wrapper mat-form-field-placeholder-wrapper"></span>
</div>
</div>
<div class="mat-input-underline mat-form-field-underline">
<span class="mat-input-ripple mat-form-field-ripple"></span>
</div>
<div class="mat-input-subscript-wrapper mat-form-field-subscript-wrapper"></div>
</div>
</mat-form-field>
</field>
</textbox>
But I'm getting "mat-form-field must contain a MatFormFieldControl" in the console. I guess this has to do with mat-form-field not directly containing a matInput-field. But it is containing it, it's just withing the ng-content projection.
Here is a blitz: https://stackblitz.com/edit/angular-xpvwzf
Angular Solutions
Solution 1 - Angular
I had this issue. I imported MatFormFieldModule
at my main module, but forgot to add MatInputModule
to the imports
array, like so:
import { MatFormFieldModule, MatInputModule } from '@angular/material';
@NgModule({
imports: [
MatFormFieldModule,
MatInputModule
]
})
export class AppModule { }
More info here.
Solution 2 - Angular
MatInputModule
Not imported
Problem 1: import MatInputModule
and MatFormFieldModule
inside module i.e. app.module.ts
import { MatInputModule } from '@angular/material/input';
import { MatFormFieldModule } from "@angular/material/form-field";
@NgModule({
imports: [
MatFormFieldModule,
MatInputModule
]
})
export class AppModule { }
Problem 2: matInput - spellings mistake / forget to add
Be sure to add matInput
and it is case-sensitive.
<mat-form-field>
<input matInput type="text" />
</mat-form-field>
Problem 3: Invalid *ngIf placement
Check that you don't have any condition on input
tag that is going to be false in any case because mat-form-field
looks for matInput
inside it. Instead put *ngIf
on mat-form-field
tag.
<mat-form-field>
<input matInput *ngIf="someCondition"> // don't add condition here, else add in mat-form-field tag
</mat-form-field>
credit to @William Herrmann for pointing out this problem#3
Problem 4: Still compiler giving ERROR
if angular compiler still giving error after fixing above given problems then you must try with restarting the app.
ng serve
Solution 3 - Angular
Import MatInputModule in your module.ts file and it will solve the problem.
import { MatInputModule } from '@angular/material/input';
The statement after it is the old answer.
Unfortunately content projection into mat-form-field
is not supported yet.
Please track the following github issue to get the latest news about it.
By now the only solution for you is either place your content directly into mat-form-field
component or implement a MatFormFieldControl
class thus creating a custom form field component.
Solution 4 - Angular
This can also happen if you have a proper input within a mat-form-field, but it has a ngIf
on it. E.g.:
<mat-form-field>
<mat-chip-list *ngIf="!_dataLoading">
<!-- other content here -->
</mat-chip-list>
</mat-form-field>
In my case, mat-chip-list
is supposed to "appear" only after its data is loaded. However, the validation is performed and mat-form-field
complains with
> mat-form-field must contain a MatFormFieldControl
To fix it, the control must be there, so I have used [hidden]
:
<mat-form-field>
<mat-chip-list [hidden]="_dataLoading">
<!-- other content here -->
</mat-chip-list>
</mat-form-field>
An alternative solution is proposed by Mosta
: move *ngIf for mat-form-field
:
<mat-form-field *ngIf="!_dataLoading">
<mat-chip-list >
<!-- other content here -->
</mat-chip-list>
</mat-form-field>
Solution 5 - Angular
Quoting from the official documentation here:
> Error: mat-form-field must contain a MatFormFieldControl
>
> This error occurs when you have not added a form field control to your form field. If your form field contains a native <input>
or <textarea>
element, make sure you've added the matInput
directive to it and have imported MatInputModule
. Other components that can act as a form field control include <mat-select>
, <mat-chip-list>
, and any custom form field controls you've created.
Learn more about creating a "custom form field control" here
Solution 6 - Angular
If anyone got stuck with this error after attempting to nest a <mat-checkbox>
, be of good cheer! It doesn't work inside a <mat-form-field>
tag.
Solution 7 - Angular
import {MatInputModule} from '@angular/material/input';
@NgModule({
imports: [
MatInputModule
],
exports: [
MatInputModule
]
})
Solution 8 - Angular
I had this issue too, and I have <mat-select>
element in my template, when I import the MatSelectModule into Module, it works, it doesn't make sense, but still I hope it can help you.
import { MatSelectModule } from '@angular/material/select';
imports: [
BrowserModule,
BrowserAnimationsModule,
MatSidenavModule,
MatButtonModule,
MatIconModule,
MatToolbarModule,
MatFormFieldModule,
MatProgressSpinnerModule,
MatInputModule,
MatCardModule,
MatSelectModule
],
<div class="example-container">
<mat-form-field>
<input matInput placeholder="Input">
</mat-form-field>
<mat-form-field>
<textarea matInput placeholder="Textarea"></textarea>
</mat-form-field>
<mat-form-field>
<mat-select placeholder="Select">
<mat-option value="option">Option</mat-option>
</mat-select>
</mat-form-field>
</div>
Solution 9 - Angular
if anyone is trying to nest a <mat-radio-group>
inside a <mat-form-field>
like below, you will get this error
<mat-form-field>
<!-- <mat-label>Image Position</mat-label> -->
<mat-radio-group aria-label="Image Position" [(ngModel)]="section.field_1">
<mat-radio-button value="left">Left</mat-radio-button>
<mat-radio-button value="right">Right</mat-radio-button>
</mat-radio-group>
</mat-form-field>
remove the parent <mat-form-field>
tags
Solution 10 - Angular
I'm not sure if it could be this simple but I had the same issue, changing "mat-input" to "matInput" in the input field resolved the problem. In your case I see "matinput" and it's causing my app to throw the same error.
<input _ngcontent-c4="" class="mat-input-element mat-form-field-autofill-control" matinput="" ng-reflect-placeholder="Personnummer/samordningsnummer" ng-reflect-value="" id="mat-input-2" placeholder="Personnummer/samordningsnummer" aria-invalid="false">
"matinput"
"matInput"
Solution 11 - Angular
If all of the main code structure/configuration answers above don't solve your issue, here's one more thing to check: make sure that you haven't in some way invalidated your <input>
tag.
For instance, I received the same mat-form-field must contain a MatFormFieldControl
error message after accidentally putting a required
attribute after a self-closing slash /
, which effectively invalidated my <input/>
. In other words, I did this (see the end of the input tag attributes):
wrong:
<input matInput type="text" name="linkUrl" [formControl]="listingForm.controls['linkUrl']" /required>
right:
<input matInput type="text" name="linkUrl" [formControl]="listingForm.controls['linkUrl']" required/>
If you make that mistake or something else to invalidate your <input>
, then you could get the mat-form-field must contain a MatFormFieldControl
error. Anyway, this is just one more thing to look for as you're debugging.
Solution 12 - Angular
Angular 9+ ...Material 9+
I have noticed 3 mistakes can can give rise to the same error:
- Ensure you have imported MatFormFieldModule and MatInputModule in the app.module or the module.ts where your components are being imported(in case of nested modules)
- When you wrap material buttons or checkbox in mat-form-field. See the list of material components that can be wrapped with mat-form-field mat-form-field
- When you fail to include matInput in your tag. i.e matInput type="number" step="0.01" formControlName="price" />
Solution 13 - Angular
I had accidentally removed the matInput directive from the input field which caused the same error.
eg.
<mat-form-field>
<input [readOnly]="readOnly" name="amount" formControlName="amount" placeholder="Amount">
</mat-form-field>
fixed code
<mat-form-field>
<input matInput [readOnly]="readOnly" name="amount" formControlName="amount" placeholder="Amount">
</mat-form-field>
Solution 14 - Angular
Unfortunately I can't just comment on some already good answers as I don't have the SO points yet, however, there are 3 key modules that you'll need to make sure you are importing into your component's parent module, aside from what you have to import into your component directly. I wanted to briefly share them and highlight what they do.
- MatInputModule
- MatFormFieldModule
- ReactiveFormsModule
The first two are for Angular Material. A lot of people new to Angular Material will instinctively come across one of these and not realize that building a form requires both.
So what's the difference between them?
MatFormFieldModule encompasses all the different types of form fields that Angular Material has available. This is more of a high level module for form fields in general, whereas the MatInputModule is specifically for 'input' field types, as opposed to select boxes, radio buttons, etc.
The third item on the above list is Angular's Reactive Forms Module. The Reactive Forms Module is responsible for a ton of under-the-hood Angular love. If you are going to work with Angular, I highly recommend that you spend some time reading Angular Docs. They have all of your answers. Building applications rarely DOESN'T involve forms, and more often than not, your application will involve reactive forms. For that reason, please take the time to read these two pages.
Angular Docs: Reactive Forms Module
The first doc 'Reactive Forms' will be your most powerful weapon as you get started, and the second doc will be your most power weapon as you get on to more advanced applications of Angular Reactive Forms.
Remember, these need to be imported directly into your component's module, not the component you are using them in. If I remember correctly, in Angular 2, we imported the entire set of Angular Material modules in our main app module, and then imported what we needed in each of our components directly. The current method is much more efficient IMO because we are guaranteed to import the entire set of Angular Material modules if we only use a few of them.
I hope this provides a bit more insight into building forms with Angular Material.
Solution 15 - Angular
The same error can occur if you have a mat slide within a mat from field as the only element in my case I had
<mat-form-field>
<mat-slide-toggle [(ngModel)]="myvar">
Some Text
</mat-slide-toggle>
</mat-form-field>
This might happen if you had several attributes within the <mat-form-field>
Simple solution was to move the slide toggle to the root
Solution 16 - Angular
You have missed matInput
directive in your input tag.
Solution 17 - Angular
New updated MatInput Module import is:
import {MatInputModule} from '@angular/material/input';
As per Angular Materials API
Solution 18 - Angular
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
don't forget to add at first of <tabe></table>
<mat-form-field>
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. Helium" #input>
</mat-form-field>
don't forget to add at last of <tabe></table>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">
No data matching the filter "{{input.value}}"
</td>
</tr>
Solution 19 - Angular
I had the problem occuring in one of my Karma tests
As most answers already pointed at, missing modules can cause problems and they must be reimported in the Karma TestBed as well. Also, it seems like we also need to import BrowserAnimationsModule to make everything work.
In my code below I have commented some modules that may not be useful for you, but the other 4 imports should definitely help !
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EventFormComponent ],
imports: [
# HttpClientTestingModule,
# RouterTestingModule,
ReactiveFormsModule,
MatFormFieldModule,
MatInputModule,
BrowserAnimationsModule,
# TranslateModule.forRoot(),
],
})
.compileComponents();
}));
Solution 20 - Angular
You could try following this guide and implement/provide your own MatFormFieldControl
Solution 21 - Angular
In my case I changed this:
<mat-form-field>
<input type="email" placeholder="email" [(ngModel)]="data.email">
</mat-form-field>
to this:
<mat-form-field>
<input matInput type="email" placeholder="email" [(ngModel)]="data.email">
</mat-form-field>
Adding the matInput directive to the input tag was what fixed this error for me.
Solution 22 - Angular
MatRadioModule won't work inside MatFormField. The docs say > This error occurs when you have not added a form field control to your > form field. If your form field contains a native or
Solution 23 - Angular
In my case, one of my closing parenthesis for "onChanges()" were missed on the input element and thus the input element was apparently not being rendered at all:
<input mat-menu-item
matInput type="text"
[formControl]="myFormControl"
(ngModelChange)="onChanged()>
Solution 24 - Angular
You might have missed to import MatInputModule
Solution 25 - Angular
A partial solution is to wrap the material form field in a custom component and implement the ControlValueAccessor
interface on it. Besides content projection the effect is pretty much the same.
See full example on Stackblitz.
I used FormControl
(reactive forms) inside CustomInputComponent
but FormGroup
or FormArray
should work too if you need a more complex form element.
app.component.html
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<mat-form-field appearance="outline" floatLabel="always" color="primary">
<mat-label>First name</mat-label>
<input matInput placeholder="First name" formControlName="firstName" required>
<mat-hint>Fill in first name.</mat-hint>
<mat-error *ngIf="firstNameControl.invalid && (firstNameControl.dirty || firstNameControl.touched)">
<span *ngIf="firstNameControl.hasError('required')">
You must fill in the first name.
</span>
</mat-error>
</mat-form-field>
<custom-input
formControlName="lastName"
[errorMessages]="errorMessagesForCustomInput"
[hint]="'Fill in last name.'"
[label]="'Last name'"
[isRequired]="true"
[placeholder]="'Last name'"
[validators]="validatorsForCustomInput">
</custom-input>
<button mat-flat-button
color="primary"
type="submit"
[disabled]="form.invalid || form.pending">
Submit
</button>
</form>
custom-input.component.html
<mat-form-field appearance="outline" floatLabel="always" color="primary">
<mat-label>{{ label }}</mat-label>
<input
matInput
[placeholder]="placeholder"
[required]="isRequired"
[formControl]="customControl"
(blur)="onTouched()"
(input)="onChange($event.target.value)">
<mat-hint>{{ hint }}</mat-hint>
<mat-error *ngIf="customControl.invalid && (customControl.dirty || customControl.touched)">
<ng-container *ngFor="let error of errorMessages">
<span *ngFor="let item of error | keyvalue">
<span *ngIf="customControl.hasError(item.key)">
{{ item.value }}
</span>
</span>
</ng-container>
</mat-error>
</mat-form-field>
Solution 26 - Angular
> You need to import the MatInputModule into your app.module.ts file > > import { MatInputModule} from '@angular/material';
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { CustomerPage } from './components/customer/customer';
import { CustomerDetailsPage } from "./components/customer-details/customer-details";
import { CustomerManagementPageRoutingModule } from './customer-management-routing.module';
import { MatAutocompleteModule } from '@angular/material/autocomplete'
import { ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule} from '@angular/material';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
CustomerManagementPageRoutingModule,
MatAutocompleteModule,
MatInputModule,
ReactiveFormsModule,
MatFormFieldModule
],
Solution 27 - Angular
You can set appearance="fill" inside your mat-form-field tag, it works for me
<form class="example-form">
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Username Or Email</mat-label>
<input matInput placeholder="Username Or Email" type="text">
</mat-form-field>
<mat-form-field class="example-full-width" appearance="fill">
<mat-label>Password</mat-label>
<input matInput placeholder="Password" type="password">
</mat-form-field>
</form>
Solution 28 - Angular
Uncaught Error: mat-form-field must contain a MatFormFieldControl.
This error occurs when 'MatInputModule' is missed in imports,
import { MatInputModule } from '@angular/material/input'
import { MatFormFieldModule } from '@angular/material/form-field'
@NgModule({
imports: [
MatInputModule ,
MatFormFieldModule
]})
importing MatInputModule in the module.ts file would help getting rid of the problem.
Solution 29 - Angular
if there is input tag under mat-form-field then each input must have matInput
Solution 30 - Angular
Note Some time Error occurs, when we use "mat-form-field" tag around submit button like:
<mat-form-field class="example-full-width">
<button mat-raised-button type="submit" color="primary"> Login</button>
</mat-form-field>
So kindly don't use this tag around submit button
Solution 31 - Angular
use providers in component.ts file
@Component({
selector: 'your-selector',
templateUrl: 'template.html',
styleUrls: ['style.css'],
providers: [
{ provide: MatFormFieldControl, useExisting: FormFieldCustomControlExample }
]
})
Solution 32 - Angular
Solution 33 - Angular
it means you are not importing MatInputModule like
import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from "@angular/material/form-field";
@NgModule({ imports: [ MatFormFieldModule, MatInputModule ] }) export class AppModule { }
Solution 34 - Angular
I had same issue
issue is simple
only you must import two modules to your project
MatFormFieldModule MatInputModule
Solution 35 - Angular
i was getting the same issue due to commented element as follows.
<mat-form-field>
<mat-label>Database</mat-label>
<!-- <mat-select>
<mat-option *ngFor="let q of queries" [value]="q.id">
{{q.name}}
</mat-option>
</mat-select> -->
</mat-form-field>
form field should have element! (e.g. the input, textarea, select, etc.)
Solution 36 - Angular
I had the module imported and directive set and after executing 'ng add @angular/material' again it started working. Maybe it would be enough just to restart app with 'ng serve'
Solution 37 - Angular
I had the same error message, but in my case, nothing above didn't fix the problem. The solution was in "label". You need to add 'mat-label' and to put your input inside 'label' tags also. Solution of my problem is in the snippet below:
<mat-label>
Username
</mat-label>
<label>
<input
matInput
type="text"
placeholder="Your username"
formControlName="username"/>
</label>
Solution 38 - Angular
This error appears also when simply by mistake input
is placed out of the mat-form-field
. To fix it just bring it inside like below:
Bad code:
<mat-form-field class="full-width">
</mat-form-field>
<input matInput placeholder="Title" formControlName="title" #title />
Fix:
<mat-form-field class="full-width">
<input matInput placeholder="Title" formControlName="title" #title />
</mat-form-field>
Solution 39 - Angular
For me the error was due to lack of <input>
and formControl property in <mat-form-field></mat-form-field>
<form [formGroup]="FormName">
<mat-form-field>
<mat-label>Name</mat-label>
</mat-form-field>
</form>
which is wrong.. Correct one is the below
<form [formGroup]="FormName">
<mat-form-field>
<mat-label>Name</mat-label>
<input matInput formControlName="name">
</mat-form-field>
</form>
Solution 40 - Angular
In my case it was the TranslocoService service which probably messes with the after init.
My code was like this :
<mat-form-field
class="fuse-mat-dense fuse-mat-no-subscript fuse-mat-rounded w-full min-w-50">
<mat-icon
class="icon-size-5"
matPrefix
[svgIcon]="'heroicons_solid:search'"></mat-icon>
<input
*transloco="let t"
(keyup.enter)="searchByCustomerName()"
matInput
[formControl]="searchInputControl"
[autocomplete]="'off'"
placeholder="{{t('customer.management.customers.search.customer.name')}}">
</mat-form-field>
I have changed it like this.
<mat-form-field
class="fuse-mat-dense fuse-mat-no-subscript fuse-mat-rounded w-full min-w-50">
<mat-icon
class="icon-size-5"
matPrefix
[svgIcon]="'heroicons_solid:search'"></mat-icon>
<input
(keyup.enter)="searchByCustomerName()"
matInput
[formControl]="searchInputControl"
[autocomplete]="'off'"
[placeholder]="searchBarPlaceHolder">
</mat-form-field>
The place holder value comes from a field at the Component. After this modification the error has gone. If you are using transloco you can try this.
Solution 41 - Angular
Every one have explained how he got this problem solved but none of the answers solved my problem and I started getting annoyed when I found out that before doing all that expalained in these answer,
> you have to install ( add ) angular material to your project
ng add @angular/material
for me this was the reason for the problem.