Search code examples
angularspring-restcontrollerform-controlformgroups

Two Way Binding FormGroup Select With Object


I have a reactive form like this

<form [formGroup]="altBirimFormu" (ngSubmit)="onSubmit()">

        <div formGroupName="detay" class="form-area">
          <h3>Detaylar</h3>
          <div class="row">
            <div class="col-md-1"><label>Birim</label></div>
            <div class="col-md-4">
              <div class="input-space">
                <select formControlName="birimControl" class="custom-select">
                  <option *ngFor="let birim of birimListesi" [ngValue] ="birim.id">
                  {{ birim.birimAdi }}</option>
                </select>
              </div>
            </div>

            <div class="col-md-2"><label>Alt Birim Adı</label></div>
            <div class="col-md-5">
              <div class="input-space">
                <input formControlName="altBirimAdi" type="text" class="form-control">
              </div>
            </div>

            <div class="col-md-2"><label>Açıklama</label></div>
            <div class="col-md-6">
              <div class="input-space">
                <textarea formControlName="aciklama" type="text" class="form-control" rows="2"></textarea>
              </div>
            </div>
            <div class="col-md-3">
              <div class="custom-control form-control-lg custom-checkbox">
                <input formControlName="aktif" type="checkbox" id="aktifMi" class="custom-control-input">
                <label for="aktifMi" class="custom-control-label">Aktif</label>
              </div>
            </div>
          </div>
        </div>

        <div class="text-center">
          <button type="submit" class="btn btn-primary">Kayıt</button>
        </div>
      </form>

And my component is like this :

altBirimFormu: FormGroup;
  birimListesi: Birim[] = [];
  seciliAltBirim: AltBirim;

  constructor(private birimService: BirimService, private formBuilder: FormBuilder,
              private altBirimService: AltBirimService, private route: ActivatedRoute,
              private alertify: AlertifyService) {
  }

  ngOnInit(): void {
    this.formuBaslat();
    this.birimleriCek();
    this.altBirimiCek();
  }

  private formuBaslat() {
    this.altBirimFormu = this.formBuilder.group({
      degerler: this.formBuilder.group({
        maxSicaklik: new FormControl('', [Validators.required, Validators.maxLength(2)]),
        minSicaklik: new FormControl('', [Validators.required, Validators.maxLength(2)]),
        maxNem: new FormControl('', [Validators.required, Validators.maxLength(2)]),
        minNem: new FormControl('', [Validators.required, Validators.maxLength(2)])
      }),
      detay: this.formBuilder.group({
        birimControl: new FormControl(''),
        altBirimAdi: new FormControl('', [Validators.required, Validators.min(3)]),
        aciklama: new FormControl(''),
        aktif: new FormControl('')
      })
    });
  }

  private birimleriCek() {
    this.birimService.getBirimList().subscribe(
      data => {
        data.forEach(
          birim => this.birimListesi.push(birim)
        );
      }
    );
  }

  private altBirimiCek() {
    const hasBirimId: boolean = this.route.snapshot.paramMap.has('id');
    if (hasBirimId) {
      this.altBirimService.getAltBirimById(+this.route.snapshot.paramMap.get('id'))
        .subscribe(
          data => {
            this.seciliAltBirim = data;
            console.log(data.birim.id)
            this.formuYarat();
          }
        );
    }
  }

  private formuYarat() {
    this.altBirimFormu = this.formBuilder.group({          
      detay: this.formBuilder.group({
        birimControl: new FormControl(this.seciliAltBirim.birim),
        altBirimAdi: new FormControl(this.seciliAltBirim.altBirimAdi, [Validators.required, Validators.min(3)]),
        aciklama: new FormControl(this.seciliAltBirim.aciklama),
        aktif: new FormControl(this.seciliAltBirim.aktif)
      })
    });

  }

Now what i want is to get information about seciliAltBirim.

I can get all the fields using altBirimiCek() and formuYarat() methods including this.seciliAltBirim.altBirimAdi, this.seciliAltBirim.aktif etc. But cannot get this.seciliAltBirim.birim into my select box. I tried using

<select formControlName="birimControl" class="custom-select">
                  <option *ngFor="let birim of birimListesi" [ngValue] ="birim">
                  {{ birim.birimAdi }}</option>
                </select>

When i submit form, i can save object properly and i can see selected object in the logs. i just can't show this object inside select box.

However if i use string values inside select box instead of object, this time i can show selected object inside options but cannot save it.

I want to know how can i bind objects two way inside select box without using string values.


Solution

  • you have to use the compareWith function provided by angular to choose which one are selected.

    <ng-container [formGroup]="altBirimFormu"> <!-- Shall be removed -->
        <select formControlName="birimControl" [compareWith]="objectComparisonFunction">
          <option *ngFor="let birim of birimListesi" [value]="birim">
            {{ birim.birimAdi }}
          </option>
        </mat-select>
    </ng-container>
    
    // Into your component.ts file
    objectComparisonFunction = function (option: Birim, value: Birim): boolean {
        return option?.id === value?.id
    }