1

I'm working on a prototype for an editor sending data according to a model to an api. Here's the model :

title: string,
desc: string,
pairs: [
  {
    left: { label: string },
    right: { label: string }
  },
  ...
]

The problem here is that I need to work with angular forms and that I can't find a way to display/use left.label and right.label.

For now, my code (shown below) works in typescript, as it's initializing the form with given values (some mock data according to the model). If I log or print my formGroup after it's been given values, it shows exactly as it should.

But my main problem is in the html of my component. Even though my formGroup is formatted well, I can't seem to use label properties (and of course, I want to edit them).

I think it's because when I create a pair in my formArray, I set only left and right properties as formControl in the group.

Here is my component.ts:

export class LinksEditorComponent implements OnInit {
  @Input() exercise;
  exerciseForm: FormGroup;

  get pairs(): FormArray {
    return this.exerciseForm.get('pairs') as FormArray;
  }

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    if (!this.exercise.title || !this.exercise.desc || !this.exercise.pairs) {
      this.exercise = {
        title: '',
        desc: '',
        pairs: []
      };
    }
    this.initExerciseForm();
  }

  initExerciseForm() {
    this.exerciseForm = this.formBuilder.group({
      title: [this.exercise.title, Validators.required],
      desc: [this.exercise.desc, Validators.required],
      pairs: this.formBuilder.array(
        this.exercise.pairs.map(pair => this.createPair(pair)),
        Validators.required
      )
    });
  }

  createPair(pair: any): FormGroup {
    return this.formBuilder.group({
      left: [{ label: pair.left.label }, Validators.required],
      right: [{ label: pair.right.label }, Validators.required]
    });
  }

  onAddPair() {
    this.pairs.push(
      this.formBuilder.group({
        left: [{ label: '' }, Validators.required],
        right: [{ label: '' }, Validators.required]
      })
    );
  }
}

And here is my component.html:

<mat-card class="links-editor" *ngIf="exercise">
  <form
    fxLayout="column"
    fxLayoutAlign="space-between center"
    [formGroup]="exerciseForm"
    (ngSubmit)="onSubmit()"
    fxLayout="column"
  >
    <mat-form-field appearance="standard">
      <mat-label>Title</mat-label>
      <input matInput formControlName="title" />
    </mat-form-field>
    <mat-form-field appearance="standard">
      <mat-label>Description</mat-label>
      <input matInput formControlName="desc" />
    </mat-form-field>
    <mat-list formArrayName="pairs">
      <div *ngFor="let pairControl of pairs.controls; let i = index">
        <div [formGroupName]="i">
          <mat-form-field appearance="standard">
            <mat-label>Left chip</mat-label>
            <input matInput formControlName="left" />
          </mat-form-field>
          <mat-form-field appearance="standard">
            <mat-label>Right chip</mat-label>
            <input matInput formControlName="right" />
          </mat-form-field>
        </div>
      </div>
      <button type="button" mat-mini-fab color="accent" (click)="onAddPair()">
        <mat-icon>add</mat-icon>
      </button>
    </mat-list>
    <button type="submit" mat-fab color="accent" [disabled]="exerciseForm.invalid">
      <mat-icon>done</mat-icon>
    </button>
  </form>
</mat-card>

If I try in the HTML file to set <input formControlName="left.input">, I've got an error in the console, and the data isn't displaying. And of course, if I set <input formControlName="left">, I got... Well left's value : [Object object].

2
  • why are you adding label for formControl Commented Aug 9, 2019 at 9:12
  • @Chellappan as you can see it's a mat-label, that's only for styling. It's just a part of Material Angular components Commented Aug 9, 2019 at 9:17

2 Answers 2

1

Okay I found the solution ! I didn't understood I could just create a FormGroup inside a FormGroup. So here's how my code looks like now, in case someone needed help :

component.ts pair creation

 createPair(pair: any): FormGroup {
    return this.formBuilder.group({
      left: this.formBuilder.group({ label: [pair.left.label, Validators.required] }),
      right: this.formBuilder.group({ label: [pair.right.label, Validators.required] })
    });
  }

  onAddPair() {
    this.pairs.push(
      this.formBuilder.group({
        left: this.formBuilder.group({ label: ['', Validators.required] }),
        right: this.formBuilder.group({ label: ['', Validators.required] })
      })
    );
  }

component.html display

<mat-list formArrayName="pairs">
      <div *ngFor="let pairControl of pairs.controls; let i = index">
        <div [formGroupName]="i">
          <mat-form-field appearance="standard" formGroupName="left">
            <mat-label>Left chip</mat-label>
            <input matInput formControlName="label" />
          </mat-form-field>
          <mat-form-field appearance="standard" formGroupName="right">
            <mat-label>Right chip</mat-label>
            <input matInput formControlName="label" />
          </mat-form-field>
        </div>
      </div>
      <button type="button" mat-mini-fab color="accent" (click)="onAddPair()">
        <mat-icon>add</mat-icon>
      </button>
</mat-list>
Sign up to request clarification or add additional context in comments.

Comments

0

object object means that you have js object that you're trying to load into the dome. Put this in the html inside the same tag as your input

<p>{{left | json}}</p>

then you should see all available properties of the left object, and then set in the formcontrolName accordingly

1 Comment

I'm not sure I get what you mean. left only got one property : label, and it contains the string I want to be able to display/edit.

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.