简体   繁体   中英

Angular V11: NullInjectorError: No provider for ControlContainer

I have a custom input made in accordance to this article: medium.com: dont-reinvent-the-wheel .

Here is my code, it is in strict mode ▼

// input.component.ts

import { Component, Input, ViewChild } from '@angular/core';
import {
    ControlContainer,
    ControlValueAccessor,
    FormControl,
    FormControlDirective,
    NG_VALUE_ACCESSOR
} from '@angular/forms';
import {
    FloatLabelType,
    MatFormFieldAppearance
} from '@angular/material/form-field';

@Component({
    selector: 'app-input',
    templateUrl: './input.component.html',
    styleUrls: ['./input.component.scss'],
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: InputComponent,
            multi: true
        }
    ]
})
export class InputComponent implements ControlValueAccessor {
    isDisabled!: boolean;

    @Input() isRequired!: boolean;

    @Input() label!: string;

    @Input() placeholder!: string;

    @Input() readonly!: boolean;

    @Input() appearance: MatFormFieldAppearance = 'fill';

    @Input() floatLabel: FloatLabelType = 'auto';

    @ViewChild(FormControlDirective, { static: true })
    formControlDirective!: FormControlDirective;

    @Input() formControl!: FormControl;

    @Input() formControlName!: string;

    get control(): FormControl {
        return (
            this.formControl ||
            this.controlContainer.control?.get(this.formControlName)
        );
    }

    constructor(private controlContainer: ControlContainer) {}

    clearInput(): void {
        this.control.setValue('');
    }

    registerOnTouched(fn: any): void {
        this.formControlDirective.valueAccessor?.registerOnTouched(fn);
    }

    registerOnChange(fn: any): void {
        this.formControlDirective.valueAccessor?.registerOnChange(fn);
    }

    writeValue(obj: any): void {
        this.formControlDirective.valueAccessor?.writeValue(obj);
    }

    setDisabledState(disabled: boolean): void {
        this.isDisabled = disabled;
    }
}
<!-- input.component.html -->

<div class="custom-input">
    <mat-form-field
        [appearance]="appearance"
        [floatLabel]="floatLabel"
        class="custom-input__form-field"
    >
        <mat-label class="custom-input__label"
            >{{ label }} <span *ngIf="isRequired && label">*</span></mat-label
        >
        <input
            class="custom-input__value"
            matInput
            type="text"
            [formControl]="$any(control)"
            [placeholder]="placeholder"
            [readonly]="readonly"
        />
        <button
            class="custom-input__clear-btn"
            matSuffix
            mat-icon-button
            aria-label="Clear"
            *ngIf="$any(control).value && !readonly"
            (click)="clearInput()"
        >
            <mat-icon>close</mat-icon>
        </button>
    </mat-form-field>
</div>

There is no compiler error but the browser log this error ▼

ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(ClientsListModule)[ControlContainer -> 
ControlContainer -> ControlContainer -> ControlContainer -> ControlContainer -> ControlContainer]: 
  NullInjectorError: No provider for ControlContainer!
NullInjectorError: R3InjectorError(ClientsListModule)[ControlContainer -> ControlContainer -> ControlContainer -> 
ControlContainer -> ControlContainer -> ControlContainer]: 
  NullInjectorError: No provider for ControlContainer!

I've checked similar questions here Angular 5: "No provider for ControlContainer" and here No provider for ControlContainer and according to them issue is in not importing both ReactiveFormsModule and FormsModule in respective module, but I am importing them and still I see that error.

在此处输入图像描述

UPDATE 1: In components <app-input> is used in the following way ▼

在此处输入图像描述

As it seems you use formControl without formGroup in some cases, so use @Optional decorator to have controlContainer null in those cases.

constructor(@Optional() private controlContainer: ControlContainer) {}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM