3

My code environment is Angular 9, and when I set up reactive form, I met this error:

error NG8002: Can't bind to 'formGroup' since it isn't a known property of 'form'.

I did some researches in Google and StackOverflow, but can't find the same questions with using Angular 9, however, based on other posts suggestions, I do import ReactiveFormsModule into app.module.ts, routing.module.ts and also recipe-edit.component.spec.ts files. However, the error keeps popping up. I attach my code, and somebody could give me suggestions?

app.module.ts

import { RecipeService } from './recipes/recipe.service';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule} from '@angular/forms';

import { RoutingModule } from './routing.module';
import { ShoppingListService } from './shopping-list/shopping-list.service';
import { AppComponent } from './app.component';
import { RecipesComponent } from './recipes/recipes.component';
import { RecipeListComponent } from './recipes/recipe-list/recipe-list.component';
import { RecipeItemComponent } from './recipes/recipe-list/recipe-item/recipe-item.component';
import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component';
import { HeaderComponent } from './header/header.component';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
import { ShoppingEditComponent } from './shopping-list/shopping-edit/shopping-edit.component';
import { DropdownDirective } from './shared/dropdown.directive';

@NgModule({
  declarations: [
    AppComponent,
    RecipesComponent,
    RecipeListComponent,
    RecipeItemComponent,
    RecipeDetailComponent,
    HeaderComponent,
    ShoppingListComponent,
    ShoppingEditComponent,
    DropdownDirective
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    RoutingModule
  ],
  providers: [ShoppingListService, RecipeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

routing.module.ts

import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RecipeStartComponent } from './recipes/recipe-start/recipe-start.component';
import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component';
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { ShoppingListComponent } from './shopping-list/shopping-list.component';
import { RecipesComponent } from './recipes/recipes.component';
import { RecipeEditComponent } from './recipes/recipe-edit/recipe-edit.component';

const routes: Routes = [
  {path: '', redirectTo: '/recipes', pathMatch: 'full'},
  {path: 'recipes', component: RecipesComponent, children: [
    {path: '', component: RecipeStartComponent},
    {path: 'new', component: RecipeEditComponent},
    {path: ':id', component: RecipeDetailComponent},
    {path: ':id/edit', component: RecipeEditComponent}
  ]},
  {path: 'shopping-list', component: ShoppingListComponent}
  ];
@NgModule({
  imports: [RouterModule.forRoot(routes), FormsModule, ReactiveFormsModule],
  exports: [RouterModule]
})
export class RoutingModule {}

recipe-edit.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { FormGroup, FormControl } from '@angular/forms';

import { RecipeService } from './../recipe.service';

@Component({
  selector: 'app-recipe-edit',
  templateUrl: './recipe-edit.component.html',
  styleUrls: ['./recipe-edit.component.css']
})
export class RecipeEditComponent implements OnInit {
  id: number;
  editMode = false;
  recipeForm: FormGroup;

  constructor(private route: ActivatedRoute, private recipeService: RecipeService) { }

  ngOnInit() {
    this.route.params
      .subscribe(
        (paras: Params) => {
          this.id = +paras.id;
          this.editMode = paras.id != null;
          this.initForm();
        }
      );
  }

  private initForm() {
    let name = '';
    let imagePath = '';
    let description = '';

    if (this.editMode) {
      const editRecipe = this.recipeService.getRecipe(this.id);
      name = editRecipe.name;
      imagePath = editRecipe.imagePath;
      description = editRecipe.desc;
    }

    this.recipeForm = new FormGroup({
      name: new FormControl(name),
      imagePath: new FormControl(imagePath),
      description: new FormControl(description)
    });
  }

  onSubmit() {
    console.log(this.recipeForm);
  }
}

recipe-edit.component.html

<div class="row">
  <div class="col-xs-12">
    <form (ngSubmit) = "onSubmit()" [formGroup] = "recipeForm" >
      <div class="row">
        <div class="col-xs-12">
          <button class="btn btn-success" type = "submit"> Save </button>
          <button class="btn btn-danger" type = "button"> Cancel </button>
        </div>
      </div>
      <div class="row">
        <div class="col-xs-12">
          <div class="form-group">
            <label for="name"> Recipe Name</label>
            <input
              type = "text"
              id = "name"
              formControlName="name"
              class="form-control">
          </div>
        </div>
      </div>
      <div class="row">
        <div class="col-xs-12">
          <div class="form-group">
            <label for="imagePath"> Image URL </label>
            <input
              type = "text"
              id = "imagePath"
              formControlName="imagePath"
              class="form-control">
          </div>
        </div>
      </div>
      <div class="row">
        <div class="col-xs-12">
          <img src="" class="img-reponsive">
        </div>
      </div>
      <div class="row">
        <div class="col-xs-12">
          <div class="form-group">
            <label for="description"> Description </label>
            <textarea
              type = "text"
              id = "description"
              formControlName="description"
              class="form-control"
              rows = "6"></textarea>
          </div>
        </div>
      </div>
      <div class="row">
        <div class="col-xs-12">
          <div class="row">
            <div class="col-xs-8">
              <input
                type = "text"
                class = "form-control">
              </div>
              <div class="col-xs-2">
                <input
                type = "number"
                class = "form-control">
            </div>
            <div class="col-xs-2">
              <button class="btn btn-danger" type = "button"> X </button>
            </div>
          </div>
        </div>
      </div>
    </form>
  </div>
</div>

recipe-edit.component.spec.ts

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { RecipeEditComponent } from './recipe-edit.component';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';

describe('RecipeEditComponent', () => {
  let component: RecipeEditComponent;
  let fixture: ComponentFixture<RecipeEditComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ RecipeEditComponent ],
      imports: [ReactiveFormsModule, FormsModule]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(RecipeEditComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});
Kate Orlova
  • 3,225
  • 5
  • 11
  • 35
John
  • 129
  • 2
  • 2
  • 9

3 Answers3

9

If the RecipeEditComponent belongs to AppModule, you need to declare the RecipeEditComponent in app.module.ts:

import { RecipeService } from './recipes/recipe.service';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule} from '@angular/forms';

import { RoutingModule } from './routing.module';
import { ShoppingListService } from './shopping-list/shopping-list.service';
import { AppComponent } from './app.component';
// Add following line:
import { RecipeEditComponent } from './recipes/recipe-edit/recipe-edit.component'; // add this
import { RecipesComponent } from './recipes/recipes.component';
import { RecipeListComponent } from './recipes/recipe-list/recipe-list.component';
import { RecipeItemComponent } from './recipes/recipe-list/recipe-item/recipe-item.component';
import { RecipeDetailComponent } from './recipes/recipe-detail/recipe-detail.component';
import { HeaderComponent } from './header/header.component';
import { ShoppingListComponent } from './shopping-list/shopping-list.component';
import { ShoppingEditComponent } from './shopping-list/shopping-edit/shopping-edit.component';
import { DropdownDirective } from './shared/dropdown.directive';

@NgModule({
  declarations: [
    AppComponent,
    RecipesComponent,
    RecipeEditComponent, // add this and the import line
    RecipeListComponent,
    RecipeItemComponent,
    RecipeDetailComponent,
    HeaderComponent,
    ShoppingListComponent,
    ShoppingEditComponent,
    DropdownDirective
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule,
    RoutingModule
  ],
  providers: [ShoppingListService, RecipeService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Otherwise if it belongs to another module, you need to import FormsModule and ReactiveFormsModule in the module which it belongs to.

Elias Soares
  • 9,884
  • 4
  • 29
  • 59
  • Thanks for your answer, that works for me. However, I still have a question about my code. I import **RecipeEditComponent** component in my routing module, also I import ReactiveFormsModule in the same file, why this doesn't work? – John Mar 29 '20 at 14:08
  • The RoutingModule is only for declaring routes. The routes will use some component that was declared in another module (usually AppModule), but that component will not be child of RoutingModule, that's why even importing the ReactiveformsModule there, it won't work. – Elias Soares Mar 29 '20 at 14:48
1

you need to import FormsModule and ReactiveFormsModule in the module which it belongs to.

import {ReactiveFormsModule, FormsModule } from '@angular/forms';

Youssef AbouEgla
  • 1,445
  • 10
  • 21
0

Need to import following in app.module.ts file:

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

formGroup is a selector for the directive named FormGroupDirective which is part of ReactiveFormsModule, is used to bind FormGroup data to a component element.

Then add it in imports array of the module like the following:

imports: [
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    ReactiveFormsModule,
    HttpClientModule
],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
Bubai
  • 9
  • 3