0

I am trying to dynamically create a nested FormArray in my Angular 6 application.

I have a quote, which has a collection of quote-items

export class Quote {
    quoteId: number;
    quoteItems: QuoteItem[]
    status: string;
}

export class QuoteItem {

    quoteItemId: number;
    description: string;
    quoteItemDetails: QuoteItemDetail[]
}

export class QuoteItemDetail {        
    quoteItemDetailId: number;
    rate: number;
    quantity: number;
    total: number;
}

I have a form that has the Quote object, where a user can click on a button to add and remove one or more QuoteItems.

This is my code where I initialise my form:

ngOnInit() {
    this.quoteForm = this.fb.group({
        status: [''],
        quoteItems: this.fb.array([])
    });
    this.addQuoteItem();
}

And this is how I get the dynamic adding and removing working:

get quoteItems() {
    return this.quoteForm.get('quoteItems') as FormArray;
}  

addQuoteItem() {
    this.quoteItems.push(this.fb.group({
        description: '',
        quoteItemDetails: this.fb.array([])
    }));
}


removeQuoteV2Item(index) {
  this.quoteV2Items.removeAt(index);
}

And my html:

<div formArrayName="quoteItems">

    <div @items *ngFor="let item of quoteItems.controls; let contentIndex=index" [formGroupName]="contentIndex">
        <input type="text" formControlName="description">
    </div>
</div>

<p>
  <a (click)="addQuoteItem()">Add Quote Item</a>
</p>

What I'm trying to do is then have the same functionality but for my QuoteItemDetail array. So a user can add one or more quoteItems, and within them add one or more QuoteItemDetails.

I'm really stuck at the first point, I can't work out how to get a form array assessor, this doesn't work as an example, as I'm not sure how to pass the index across:

get quoteItemDetails() {
  return this.quoteItems.get('quoteItemDetails') as FormArray;
}
1
  • 2
    check David's response. Well, he forgot a formArrayName, but the idea is good:not use a getter, use a normal function that you pass the index as argument. If you want see your example, I hope this statblitz stackblitz.com/edit/… help you Commented Jan 13, 2020 at 0:26

1 Answer 1

1

You will not be able to do it with an accessor. The accessor is going to give you a reference to one attribute. But as you said, in this case you need an index to specify what quoteItemDetails FormArray reference you need (since as far as I understand you want a FormArray in each quoteItem, so each quoteItem can have several quoteItemDetails, right?).

I don't see a problem with that though. Instead of doing it with an accessor like you have done with the quoteItems, you will have to do it with a method taking the one parameter you need, the index. Something like this:

quoteItemDetails(quoteItemIndex: number): FormArray {
  return this.quoteItems.at(quoteItemIndex).get('quoteItemDetails') as FormArray;
}

And then you represent it on the template:

<div formArrayName="quoteItems">

  <div @items *ngFor="let item of quoteItems.controls; let contentIndex=index" [formGroupName]="contentIndex">
    <input type="text" formControlName="description">
    <div *ngFor="let quoteItemDetail of quoteItemDetails(contentIndex).controls; let detailIndex=index" [formArrayName]="detailIndex">
      <input type="number" formControlName="description" />
    </div>
  </div>
</div>

I hope this helps you. I have not tested the code but the solution should be someshere along these lines.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, was able to solve this with yours and @Eliseo's help

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.