1

I am having problem accesssing products array located inside opticanOrders which is inside orderForm. In the console, I see that in order to access products array, I should reference it like that:

orderForm.controls.opticianOrders.controls.products.controls

But it doesn't work.

This is my component:

  constructor(private customerService: CustomerService, private fb: FormBuilder) { }

  orderForm: FormGroup;

  ngOnInit() {
    this.orderForm = this.fb.group({
      name: [''],
      surName: [''],
      opticianOrders: this.fb.group({
        orderDescription: [''],
        products: this.fb.array([
          this.initProduct()
        ])
      }),
    });
  }

  save(model: Customer) {
    // call API to save customer
    console.log(model);
  }

  onCancel(form: NgForm){
    this.createState.emit(false);
  }

  initProduct(){
    return this.fb.group({
      name: [''],
      manufacturerName: ['']
    })
  }

  addProduct(){
    const control = <FormArray>this.orderForm.controls['products'];
    control.push(this.initProduct());
  }

  removeProduct(i: number){
    const control = <FormArray>this.orderForm.controls['products']
  }

Html

<form [formGroup]="orderForm" novalidate (ngSubmit)="save(orderForm)">

  <!-- name -->
  <div class="form-group">
      <label>Name</label>
      <input type="text" formControlName="name">
  </div>

  <!-- surName -->
  <div class="form-group">
      <label>Last Name</label>
      <input type="text" formControlName="surName">
  </div>

  <div formGroupName="opticianOrders" class="form-group">
      <label>Order Description</label>
      <input type="text" formControlName="orderDescription">
  </div>
  <div formArrayName="products">
          <div *ngFor="let product of orderForm.controls.opticianOrders.controls.products.controls; let i=index">
              <div>
                  <span>Address {{i + 1}}</span>
                  <span *ngIf="orderForm.controls.opticianOrders.controls.products.controls.length > 1" 
                      (click)="removeProduct(i)">
                  </span>
               </div>

               <div [formGroupName]="i">
                  <div>
                      <label>Product name</label>
                      <input type="text" formControlName="name">
                  </div>
              </div>
          </div>
        </div>
    <button type="submit" [disabled]="!orderForm.valid">Submit</button>
</form>
5
  • I didn't understand, what is opticianOrders?? and why did you create a fb goup again inside fb group?? Commented Sep 25, 2018 at 17:11
  • Please mention here, what kind of object you want finally?? Commented Sep 25, 2018 at 17:18
  • @Raj opticianOrders was wrong I accidentally wrote it. Fb group inside of an fb group because I want this result: { name: '', opticianOrder:{products[{name: ""}] }} Commented Sep 25, 2018 at 17:18
  • I suppose you've imported the ReactiveFormsModule in your own project? Because in your Stackblitz it's missing. Commented Sep 25, 2018 at 17:41
  • Please check below answer...It might work?? Commented Sep 25, 2018 at 18:24

3 Answers 3

2

Please replace your HTML Code as per below

<form [formGroup]="orderForm" (ngSubmit)="save()">

  <!-- name -->
  <div class="form-group">
    <label>Name</label>
    <input type="text" formControlName="name">
  </div>

  <!-- surName -->
  <div class="form-group">
    <label>Last Name</label>
    <input type="text" formControlName="surName">
  </div>

  <div class="form-group">
    <label>Order Description</label>
    <input type="text" formControlName="orderDescription">
  </div>
  <div formArrayName="products">
    <div *ngFor="let product of orderForm.controls.products['controls']; let i=index">
      <div>
        <span><strong>Product {{i + 1}}</strong></span>
        <span class="fa fa-times" *ngIf="orderForm.controls['products'].controls.length > 1" (click)="removeProduct(i)">
        </span>
      </div>

      <div [formGroupName]="i">
        <div>
          <label>Product name</label>
          <input type="text" formControlName="name">
        </div>
        <div>
          <label>Product Manufacturer name</label>
          <input type="text" formControlName="manufacturerName">
        </div>
      </div>
    </div>

    <div class="margin-20">
      <a (click)="addProduct()" style="cursor: pointer; text-transform: uppercase; font-weight: 500">
        Add another Entry +
      </a>
    </div>
  </div>
  <button class="btn btn-primary" type="submit" [disabled]="orderForm.invalid">Submit</button>
</form>

Please replace TS code as per below. I have used a trick in save form method, check whether it works for you or not?

  constructor(private fb: FormBuilder) { }

  orderForm: FormGroup;

  ngOnInit() {
    this.orderForm = this.fb.group({
      name: ['', Validators.required],
      surName: ['', Validators.required],
      orderDescription: ['', Validators.required],
      products: this.fb.array([
        this.initProduct()
      ])
    });
  }

  save() {
    console.log(this.orderForm.value);
    const obj = {
      name: this.orderForm.value.name,
      surName: this.orderForm.value.surName,
      orderDescription: this.orderForm.value.orderDescription,
      opticianOrders: {
        products: this.orderForm.value.products
      },
    };

    console.log(obj);
  }

  initProduct() {
    return this.fb.group({
      name: ['', Validators.required],
      manufacturerName: ['', Validators.required]
    })
  }

  addProduct() {
    const control = <FormArray>this.orderForm.controls['products'];
    control.push(this.initProduct());
  }

  removeProduct(i: number) {
    const control = <FormArray>this.orderForm.controls['products'];
    control.removeAt(i);
  }
Sign up to request clarification or add additional context in comments.

Comments

0

Your stackblitz code does not work. You did not import the ReactiveFormsModule and you implemented the forms code in the hello.component.ts also you put the template code in the app.component.html.

See my working sample on stackblitz. It let you add (click on Add) and remove (click on 'x') products from your FormArray.

Form value with two products:

{
  name: 'John',
  surName: 'Doe',
  opticianOrders: {
    orderDescription: '1234',
    products: [
      { name: 'Cookies', manufacturerName: '' },
      { name: 'More Cookies', manufacturerName: '' }
    ]
  }
}

For typescript this.orderForm.controls.opticianOrders is an AbstractControl which has no controls property. You have to cast it to a FormGroup first. Same with products, you have to cast it to a FormArray.

removeProduct(i: number){
  const aFormGroup = this.orderForm.controls.opticianOrders as FormGroup;
  const aFormArray = aFormGroup.controls.products as FormArray;
  aFormArray.removeAt(i);    
}

1 Comment

thank you very much, I am just starting to use angular.
0

Try this

orderForm.controls.opticianOrders.controls

3 Comments

Hi @Joseph! It doesn't work. I also update the code: it is orderForm.controls.opticianOrders.controls.products.controls and not orderForm.controls.ordersDescription.controls I accidentally typed
@flyingpig. Can you replicate in stackblitz?
Hi @Joseph this is the link to stackblitz stackblitz.com/edit/angular-ldctip.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.