0

I am getting the following error when trying to populate a FormArray in Angular (version 17):

Argument of type 'FormGroup<{ name: FormControl<string | null>; amount: FormControl<number | null>; }>' is not assignable to parameter of type 'never'.ts(2345)

This issue happens in line 44 when I try to push the FormGroup (with all the FormControls) in the FormArray. Also, I've tried using FormBuilder with the fb.group() and tried also to cast the FormArray to no good results. I don't know what to do next to solve this issue. I've tried ChatGPT, the internet, and Angular documents. Also, I think the error is misleading as I think there is something hidden that I'm not seeing for this particular Angular version (17).

Here's my code:

import { Component, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params } from '@angular/router';
import { RecipeService } from '../recipe.service';

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

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

  ngOnInit(): void { // This is an angular Observable which is going to be managed/destroy by Angular
    // If you create a custom Observable you need to destroy it manually...!!!!
    this.route.params.subscribe(
      (params: Params) => {
        this.id = +params['id']
        this.editMode = params['id'] != null
        this.initForm()
      }
    )
  }

  private initForm(){
    let recipeName = ''
    let recipeImagePath = ''
    let recipeDescription = ''
    let recipeIngredients = new FormArray([])

    if(this.editMode){
      const recipe = this.recipeService.getRecipe(this.id)
      recipeName = recipe.name
      recipeImagePath = recipe.imagePath
      recipeDescription = recipe.description
      if(recipe['ingredients']){
        for(let ingredient of recipe['ingredients']){
          recipeIngredients.push( new FormGroup({
            'name':  new FormControl(ingredient.name),
            'amount': new FormControl(ingredient.amount)
          });
        }
      }
    }
    this.recipeForm = new FormGroup({
      'name': new FormControl(recipeName),
      'imagePath': new FormControl(recipeImagePath),
      'description': new FormControl(recipeDescription),
      'ingredients': recipeIngredients
    })
  }

  get controls() { // a getter!
  return (<FormArray>this.recipeForm.get('ingredients')).controls;
}

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

}

Here's the ng version: Angular Version

2 Answers 2

1

In the latest Angular version, Reactive Forms are Typed Forms.

You need to define the type for your recipeIngredients FormArray.

export interface IngredientForm {
  name: FormControl<string>;
  amount: FormControl<number>;
}
let recipeIngredients: FormArray<FormGroup<IngredientForm>> = new FormArray(
  [] as FormGroup<IngredientForm>[]
);
get controls() { // a getter!
  return (<FormArray<FormGroup<IngredientForm>>>this.recipeForm.get('ingredients')).controls;
}
Sign up to request clarification or add additional context in comments.

1 Comment

This worked just fine. The only thing I had to add in the Interface was the type annotation of null: export interface IngredientForm { name: FormControl<string | null>; amount: FormControl<number | null>; }
0

This is the code after the fixes suggested by Yong Shun:

import { Component, OnInit } from '@angular/core';
import { FormArray, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Params } from '@angular/router';
import { RecipeService } from '../recipe.service';

export interface IngredientForm {
  'name': FormControl<string | null>;
  'amount': FormControl<number | null>;
}

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

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

  ngOnInit(): void { // This is an angular Observable which is going to be managed/destroy by Angular
    // If you create a custom Observable you need to destroy it manually...!!!!
    this.route.params.subscribe(
      (params: Params) => {
        this.id = +params['id']
        this.editMode = params['id'] != null
        this.initForm()
      }
    )
  }

  private initForm(){
    let recipeName = ''
    let recipeImagePath = ''
    let recipeDescription = ''
    let recipeIngredients: FormArray<FormGroup<IngredientForm>> = new FormArray(
      [] as FormGroup<IngredientForm>[]
    );

    if(this.editMode){
      const recipe = this.recipeService.getRecipe(this.id)
      recipeName = recipe.name
      recipeImagePath = recipe.imagePath
      recipeDescription = recipe.description
      if(recipe['ingredients']){
        for(let ingredient of recipe['ingredients']){
          const newFormGroup = new FormGroup({
            'name':  new FormControl(ingredient.name, Validators.required),
            'amount': new FormControl(ingredient.amount, Validators.required)
          })
          recipeIngredients.push(newFormGroup)
        }
      }
    }
    this.recipeForm = new FormGroup({
      'name': new FormControl(recipeName),
      'imagePath': new FormControl(recipeImagePath),
      'description': new FormControl(recipeDescription),
      'ingredients': recipeIngredients
    })
  }

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

  get controls() { // a getter!
    return (<FormArray<FormGroup<IngredientForm>>>this.recipeForm.get('ingredients')).controls;
  }

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.