No provider for ControlContainer and No provider for ControlContainer

13,979

Import both Forms Module and ReactiveFormsModule from @angular/forms in the file app.module.ts

Share:
13,979

Related videos on Youtube

Dea
Author by

Dea

Updated on June 04, 2022

Comments

  • Dea
    Dea almost 2 years

    I am working on an application using Angular2. I am trying to use Reactive Forms in my application but I am running into some errors :

    The first error is about NgControl as below:

    No provider for NgControl ("

    div class="col-md-8" [ERROR ->]input class="form-control" id="productNameId" "): ProductEditComponent@16:24

    The second error is about ControlContainer as below:

    No provider for ControlContainer (" div [ERROR ->]div formArrayName="tags">

    div class="row">

    button cl"):

    Htmm file is as below:

     <div class="panel panel-primary">
       <div class="panel-heading">
          {{pageTitle}}
    </div>
    
    <div class="panel-body">
        <form class="form-horizontal"
              novalidate
              (ngSubmit)="saveProduct()"
              formGroup="productForm" >
            <fieldset>
                <div class="form-group" 
                     [ngClass]="{'has-error': displayMessage.productName }">
                    <label class="col-md-2 control-label" for="productNameId">Product Name</label>
    
                    <div class="col-md-8">
                        <input class="form-control" 
                                id="productNameId" 
                                type="text" 
                                placeholder="Name (required)" 
                                formControlName="productName" />
                        <span class="help-block" *ngIf="displayMessage.productName">
                                {{displayMessage.productName}}
                        </span>
                    </div>
                </div>
    
    
     <div formArrayName="tags">
                    <div class="row">
                        <button class="col-md-offset-1 col-md-1 btn btn-default"
                                type="button"
                                (click)="addTag()">Add Tag
                        </button>
                    </div>
                    <div class="form-group"
                        *ngFor="let tag of tags.controls; let i=index" >
                        <label class="col-md-2 control-label" [attr.for]="i">Tag</label>
    
                        <div class="col-md-8">
                            <input class="form-control" 
                                    [id]="i" 
                                    type="text" 
                                    placeholder="Tag" 
                                    formControlName="i" />
                        </div>
                    </div>
                </div>
        <!--more piece of code here -->
    

    My component file is as below:

             import { Component, OnInit, AfterViewInit, OnDestroy, ViewChildren, ElementRef } from '@angular/core';
             import { FormBuilder, FormGroup, FormControl, FormArray, Validators, FormControlName,NgForm } from '@angular/forms';
             import { ActivatedRoute, Router  } from '@angular/router';
    
           import 'rxjs/add/operator/debounceTime';
           import 'rxjs/add/observable/fromEvent';
           import 'rxjs/add/observable/merge';
             import { Observable } from 'rxjs/Observable';
             import { Subscription } from 'rxjs/Subscription';
    
             import { IProduct } from './product';
             import { ProductService } from './product.service';
    
             import { NumberValidators } from '../shared/number.validator';
             import { GenericValidator } from '../shared/generic-validator';
    
      @Component({
          templateUrl: './product-edit.component.html'
       })
      export class ProductEditComponent implements OnInit, AfterViewInit, OnDestroy {
        @ViewChildren(FormControlName, { read: ElementRef }) formInputElements: ElementRef[];
    
    pageTitle: string = 'Product Edit';
    errorMessage: string;
    productForm: FormGroup;
    
    product: IProduct;
    private sub: Subscription;
    
    // Use with the generic validation message class
    displayMessage: { [key: string]: string } = {};
    private validationMessages: { [key: string]: { [key: string]: string } };
    private genericValidator: GenericValidator;
    
    get tags(): FormArray {
        return <FormArray>this.productForm.get('tags');
    }
    
    constructor(private fb: FormBuilder,
                private route: ActivatedRoute,
                private router: Router,
                private productService: ProductService) {
    
        // Defines all of the validation messages for the form.
        // These could instead be retrieved from a file or database.
        this.validationMessages = {
            productName: {
                required: 'Product name is required.',
                minlength: 'Product name must be at least three characters.',
                maxlength: 'Product name cannot exceed 50 characters.'
            },
            productCode: {
                required: 'Product code is required.'
            },
            starRating: {
                range: 'Rate the product between 1 (lowest) and 5 (highest).'
            }
        };
    
        // Define an instance of the validator for use with this form, 
        // passing in this form's set of validation messages.
        this.genericValidator = new GenericValidator(this.validationMessages);
    }
    
    ngOnInit(): void {
        this.productForm = this.fb.group({
            productName: ['', [Validators.required,
                               Validators.minLength(3),
                               Validators.maxLength(50)]],
            productCode: ['', Validators.required],
            starRating: ['', NumberValidators.range(1, 5)],
            tags: this.fb.array([]),
            description: ''
        });
    
        // Read the product Id from the route parameter
        this.sub = this.route.params.subscribe(
            params => {
                let id = +params['id'];
                this.getProduct(id);
            }
        );
    }
    
    ngOnDestroy(): void {
        this.sub.unsubscribe();
    }
    
    ngAfterViewInit(): void {
        // Watch for the blur event from any input element on the form.
        let controlBlurs: Observable<any>[] = this.formInputElements
            .map((formControl: ElementRef) => Observable.fromEvent(formControl.nativeElement, 'blur'));
    
        // Merge the blur event observable with the valueChanges observable
        Observable.merge(this.productForm.valueChanges, ...controlBlurs).debounceTime(800).subscribe(value => {
            this.displayMessage = this.genericValidator.processMessages(this.productForm);
        });
    }
    
    addTag(): void {
        this.tags.push(new FormControl());
    }
    
    getProduct(id: number): void {
        this.productService.getProduct(id)
            .subscribe(
                (product: IProduct) => this.onProductRetrieved(product),
                (error: any) => this.errorMessage = <any>error
            );
    }
    
    onProductRetrieved(product: IProduct): void {
        if (this.productForm) {
            this.productForm.reset();
        }
        this.product = product;
    
        if (this.product.id === 0) {
            this.pageTitle = 'Add Product';
        } else {
            this.pageTitle = `Edit Product: ${this.product.productName}`;
        }
    
        // Update the data on the form
        this.productForm.patchValue({
            productName: this.product.productName,
            productCode: this.product.productCode,
            starRating: this.product.starRating,
            description: this.product.description
        });
        this.productForm.setControl('tags', this.fb.array(this.product.tags || []));
    }
    
    deleteProduct(): void {
        if (this.product.id === 0) {
            // Don't delete, it was never saved.
            this.onSaveComplete();
       } else {
            if (confirm(`Really delete the product: ${this.product.productName}?`)) {
                this.productService.deleteProduct(this.product.id)
                    .subscribe(
                        () => this.onSaveComplete(),
                        (error: any) => this.errorMessage = <any>error
                    );
            }
        }
    }
    
    saveProduct(): void {
        if (this.productForm.dirty && this.productForm.valid) {
            // Copy the form values over the product object values
            let p = Object.assign({}, this.product, this.productForm.value);
    
            this.productService.saveProduct(p)
                .subscribe(
                    () => this.onSaveComplete(),
                    (error: any) => this.errorMessage = <any>error
                );
        } else if (!this.productForm.dirty) {
            this.onSaveComplete();
        }
    }
    
    onSaveComplete(): void {
        // Reset the form to clear the flags
        this.productForm.reset();
        this.router.navigate(['/products']);
       }
     }
    

    I am trying to solve this problem for more than 2 days but I still do not have a solution. I have seen many other answers in stackoverflow but none of them is solving my problem.

    • R. Richards
      R. Richards about 7 years
      Have you properly imported the FormModule and ReactiveFormsModule in your main application module, or other appropriate module?
  • Robert Smith
    Robert Smith about 4 years
    And if this is a tabbed application import in tab1.module.ts