Angular: mat-form-field must contain a MatFormFieldControl

76,587

Solution 1

Need to import two module and add those in imports and exports section.

import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';

@NgModule ({
  imports: [ MatFormFieldModule, MatInputModule ],
  exports: [ MatFormFieldModule, MatInputModule ]
})

And the most thing which everybody miss this '/' character. if you see the Angular Material Documentation , they also miss this (Last Checked 16 Jun 2020, don't know they even updated or not). I make an example for clarifications

<!-- Wrong -->
<mat-form-field>
  <input matInput>
</mat-form-field>

<!-- Right -->
<mat-form-field>
  <input matInput />
</mat-form-field>

Look at the snippet carefully. when <input begin it must close with /> but most people miss the / (backslash) character.

Solution 2

Make sure MatInputModule is imported and <mat-form-field> contains <input> with matInput / matSelect directives.

https://github.com/angular/material2/issues/7898

Solution 3

Import MatInputModule, solved my error

Solution 4

You need to specify your class as a provider for MatFormFieldControl

https://material.angular.io/guide/creating-a-custom-form-field-control#providing-our-component-as-a-matformfieldcontrol

@Component({
  selector: 'form-field-custom-control-example',
  templateUrl: 'form-field-custom-control-example.html',
  styleUrls: ['form-field-custom-control-example.css'],
  providers: [
    { provide: MatFormFieldControl, useExisting: FormFieldCustomControlExample }   
  ]
})

Solution 5

Also, don't forget to write the name attribute in the input tag:

name="yourName"
Share:
76,587

Related videos on Youtube

user3590450
Author by

user3590450

Updated on December 07, 2021

Comments

  • user3590450
    user3590450 over 2 years

    I am trying to add a form field with custom telephone number input control. I used the example of the phone from https://material.angular.io/components/form-field/examples.

    Here is the code:

    <mat-form-field>
      <example-tel-input placeholder="Phone number" required></example-tel-input>
      <mat-icon matSuffix>phone</mat-icon>
      <mat-hint>Include area code</mat-hint>
    </mat-form-field>
    
    import {FocusMonitor} from '@angular/cdk/a11y';
    import {coerceBooleanProperty} from '@angular/cdk/coercion';
    import {Component, ElementRef, Input, OnDestroy} from '@angular/core';
    import {FormBuilder, FormGroup} from '@angular/forms';
    import {MatFormFieldControl} from '@angular/material';
    import {Subject} from 'rxjs';
    
    /** @title Form field with custom telephone number input control. */
    @Component({
      selector: 'form-field-custom-control-example',
      templateUrl: 'form-field-custom-control-example.html',
      styleUrls: ['form-field-custom-control-example.css'],
    })
    export class FormFieldCustomControlExample {}
    
    /** Data structure for holding telephone number. */
    export class MyTel {
      constructor(public area: string, public exchange: string, public subscriber: string) {}
    }
    
    /** Custom `MatFormFieldControl` for telephone number input. */
    @Component({
      selector: 'example-tel-input',
      templateUrl: 'example-tel-input-example.html',
      styleUrls: ['example-tel-input-example.css'],
      providers: [{provide: MatFormFieldControl, useExisting: MyTelInput}],
      host: {
        '[class.example-floating]': 'shouldLabelFloat',
        '[id]': 'id',
        '[attr.aria-describedby]': 'describedBy',
      }
    })
    export class MyTelInput implements MatFormFieldControl<MyTel>, OnDestroy {
      static nextId = 0;
    
      parts: FormGroup;
      stateChanges = new Subject<void>();
      focused = false;
      ngControl = null;
      errorState = false;
      controlType = 'example-tel-input';
      id = `example-tel-input-${MyTelInput.nextId++}`;
      describedBy = '';
    
      get empty() {
        const {value: {area, exchange, subscriber}} = this.parts;
    
        return !area && !exchange && !subscriber;
      }
    
      get shouldLabelFloat() { return this.focused || !this.empty; }
    
      @Input()
      get placeholder(): string { return this._placeholder; }
      set placeholder(value: string) {
        this._placeholder = value;
        this.stateChanges.next();
      }
      private _placeholder: string;
    
      @Input()
      get required(): boolean { return this._required; }
      set required(value: boolean) {
        this._required = coerceBooleanProperty(value);
        this.stateChanges.next();
      }
      private _required = false;
    
      @Input()
      get disabled(): boolean { return this._disabled; }
      set disabled(value: boolean) {
        this._disabled = coerceBooleanProperty(value);
        this.stateChanges.next();
      }
      private _disabled = false;
    
      @Input()
      get value(): MyTel | null {
        const {value: {area, exchange, subscriber}} = this.parts;
        if (area.length === 3 && exchange.length === 3 && subscriber.length === 4) {
          return new MyTel(area, exchange, subscriber);
        }
        return null;
      }
      set value(tel: MyTel | null) {
        const {area, exchange, subscriber} = tel || new MyTel('', '', '');
        this.parts.setValue({area, exchange, subscriber});
        this.stateChanges.next();
      }
    
      constructor(fb: FormBuilder, private fm: FocusMonitor, private elRef: ElementRef<HTMLElement>) {
        this.parts = fb.group({
          area: '',
          exchange: '',
          subscriber: '',
        });
    
        fm.monitor(elRef, true).subscribe(origin => {
          this.focused = !!origin;
          this.stateChanges.next();
        });
      }
    
      ngOnDestroy() {
        this.stateChanges.complete();
        this.fm.stopMonitoring(this.elRef);
      }
    
      setDescribedByIds(ids: string[]) {
        this.describedBy = ids.join(' ');
      }
    
      onContainerClick(event: MouseEvent) {
        if ((event.target as Element).tagName.toLowerCase() != 'input') {
          this.elRef.nativeElement.querySelector('input')!.focus();
        }
      }
    
    
      }
    

    example-tel-input-example.html

      <div [formGroup]="parts" class="example-tel-input-container">
          <input class="example-tel-input-element" formControlName="area" size="3">
          <span class="example-tel-input-spacer">&ndash;</span>
          <input class="example-tel-input-element" formControlName="exchange" size="3">
          <span class="example-tel-input-spacer">&ndash;</span>
          <input class="example-tel-input-element" formControlName="subscriber" size="4">
        </div>
    

    But I get the following error:

    ERROR Error: mat-form-field must contain a MatFormFieldControl.

  • mlapaglia
    mlapaglia over 3 years
    oh wow thank you so much, copied their example right off the page and couldn't get it to work!
  • Bassem
    Bassem over 2 years
    Thanks , very helpful