0

I am having a calendar which is essentially represents a huge form. At the moment there is not a lot to see but what for now it gets a list of dates from which I start to build up a form:

this.dates.forEach(d => {
  group[d] = this._formBuilder.group({
    offers: this._formBuilder.array([])
  });
});

So, what I actually want is this: A map from date to a list of items

{
  '2018-01-01': [{id: 1}, {id: 2}],
  '2018-01-02': [{id: 5}, {id: 9}]
}

However, following this tutorial it seems I am currently ending up with something like:

{
  '2018-01-01': {offers: [{id: 1}, {id: 2}]},
  '2018-01-02': {offers: [{id: 5}, {id: 9}]}
}

which is good enough for me - I just want this to work.

I am passing down the offers form group in the parent component:

<form [formGroup]="form" *ngIf="form != null">  
  <div fxLayout="row" >  
    <app-calendar-day *ngFor="let date of dates$ | async" 
                      [formGroup]="form.get(date)">
    </app-calendar-day>  
  </div>  
</form>

This is working so far.

My problems start at the final step where I want to add offers/items to the FormArray.

<div [formGroup]="formGroup">
  <mat-card *ngFor="let offer of formGroup.get('offers').controls; let idx = index" style="margin: 4px; padding: 10px;">
    <app-offer-item [formGroupName]="idx">
    </app-offer-item>
  </mat-card>
</div>

The calendar allows to add items/offers and I want formGroup.get('offers') (the FormArray) to be built up dynamically s.t. I can post the entire thing at the end ot the day.

However, I do not know how to bind the offer/item correctly.

The app-offer-item is built on AbstractControlComponent which delivers ControlValueAccessor and Validator interfaces as well as some default implementations. The code for OfferItemComponent aka app-offer-item is below. Since it encapsulates an object, I am quite certain that this element should represent a FormGroup but I am not able to wire the pieces together correctly as it seems.

The code above is giving me

ERROR Error: Cannot find control with unspecified name attribute

This seems to happen right after I add an item/offer to the FormArray:

onAddOffer(offer) {
  const formArray = <FormArray> this.formGroup.get('offers');
  formArray.push(this._formBuilder.group(offer));
  // ..
}

I expected writeValue() in OfferItemComponent to be called somehow but I guess that's not how it works.

I think I have two options here:

  1. Find a way to make this work after all
  2. Pass down the additional FormGroup to OfferItemComponent and try to make it work like that

Any help is very much appreciated!


OfferItemComponent

@Component({
  selector: 'app-offer-item',
  styles: [`
  `],
  template: `
    <div>      
      <div [innerHTML]="getItemHtml()"></div>

      <div>
        <span style="padding-right: 4px;">€</span>
        <mat-form-field style="text-align: right; width: 55px; margin-bottom: -1.25em;">
          <input matInput autocomplete="off" (focusout)="formatPrice($event.target)"/>
        </mat-form-field>        
      </div>

    </div>
  `,
  providers: [
    DecimalPipe,
    ValueAccessorProvider(OfferItemComponent),
    ValidatorsProvider(OfferItemComponent)
  ]
})
export class OfferItemComponent extends AbstractControlComponent {
  @Input()
  items;

  offer: OfferModel;

  constructor(
    @Inject(LOCALE_ID) public locale: string,
    private _decimalPipe: DecimalPipe
  ) {
    super();
  }

  writeValue(offer: OfferModel): void {
    this.offer = offer;
    this._onChangeCallback(this.offer);
  }

  validate(c: AbstractControl): ValidationErrors | any {
    // ..
  }

  getItemHtml() {
    // ..
  }

  formatPrice(element) {
    // ..
  }

}
1
  • I used template driven forms and I was able access each element with just having #someForm="ngForm", I have not tried with Reactive forms Commented Oct 28, 2018 at 20:36

2 Answers 2

1

I believe that all of your form control elements within a [formGroup] need to have the "name" and the "formControlName" attribute set as well.

[attr.data-name]="name_of_field" [formControlName]="name_of_field"
Sign up to request clarification or add additional context in comments.

Comments

0

The missing element in your code is formArrayName

<div formArrayName="offers">
  <mat-card *ngFor="let offer of formGroup.get('offers').controls; let idx = index" style="margin: 4px; padding: 10px;">
    <app-offer-item [formGroupName]="idx">
    </app-offer-item>
  </mat-card>
</div>

2 Comments

Thank you. I'll take a look at this tomorrow right after work!
I was not able to solve it like this. After all I decided to pass doen the FormArray and iterate over it's content (list of FormGroups) to pass those further down.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.