No provider for ControlContainer and No provider for ControlContainer

Dea picture Dea · Mar 22, 2017 · Viewed 13.3k times · Source

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.

Answer

Ayushi Jain picture Ayushi Jain · Mar 16, 2018

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