0

I have a an inelegant solution to a problem I'm having looping data from an observable. I would like to know the correct way to do it because this doesn't seem right to me.

I am dynamically creating a form using the response from an api call

This is my component

export class NewProductGeneralComponent implements OnInit, OnDestroy {
  productTitles: [];
  subscription: Subscription;
  startform  = false;
  productDescFormGroup: FormGroup;
  group = {};
  constructor(
    private apiservice: ApiService
  ) { }

  getProductColumns() {
    this.apiservice.getProductTable('/api/products-columns')
      .subscribe( res =>  {
        this.productTitles = res;
        for(const k in this.productTitles) {
          this.group[k] = new FormControl('');
        }
      });
  }

  ngOnInit() {
    this.getProductColumns();
    setTimeout(() => {
      this.productDescFormGroup = new FormGroup(this.group);
      this.startform = true;
    }, 300);
  }

  ngOnDestroy(): void {
    this.subscription.unsubscribe();
  }

  onSubmit() {
    console.log(this.productDescFormGroup.value);
  }

}

This is my template


<ng-container *ngIf="startform">
  <form [formGroup]="productDescFormGroup" (ngSubmit)="onSubmit()">
    <div *ngFor="let form_elem of productTitles| keyvalue">
      <div [ngSwitch]="form_elem.value">

        <fieldset *ngSwitchCase="'string'">
          <label> {{ form_elem.key.replace('_', ' ') }} </label>
          <input type="text" formControlName="{{form_elem.key}}" />
        </fieldset>

        <fieldset *ngSwitchCase="'decimal'">
          <label> {{ form_elem.key.replace('_', ' ') }} </label>
          <input type="number" formControlName="{{form_elem.key}}" />
        </fieldset>

        <fieldset *ngSwitchCase="'boolean'">
          <label> {{ form_elem.key.replace('_', ' ') }} </label>
          <select formControlName="{{form_elem.key}}" >
            <option value="">Select Value</option>
            <option value="1">Yes</option>
            <option value="0">No</option>
          </select>
        </fieldset>

      </div>
    </div>
    <input type="submit" value="SAVE" class="btn btn-sm btn-danger"
    [disabled]="productDescFormGroup.invalid" />
  </form>
</ng-container>

My problem is that if I don't put in a timeout, the formgroup doesn't initialise so on submit nothing comes through plus the submit button is enabled even when the form isn't complete. How do I fix this without using a timeout?

mr_j
  • 125
  • 1
  • 15
  • I would like to suggest to you use resolver, basically resolver is kind of intermediate code,which will executed before component is loaded, by using this you will b able to get data before component will load and no need to put timeout.. – kushal shah Jan 28 '20 at 07:08
  • @kushalshah I followed your suggestion and it worked. Thanks! – mr_j Jan 28 '20 at 09:31

1 Answers1

0

Just for anyone who might have a similar problem. The answer is to use resolvers which run when the route is initialised and get data from service

Below is the code for the route

  {
    path: 'products/add-product',
    component: AddProductPageComponent,
    resolve: { productTitles: ProductTitlesResolver }
  },

The resolver

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { ApiService } from '../index';

@Injectable({
  providedIn: 'root'
})
export class ProductTitlesResolver implements Resolve<Observable<string>> {

  constructor( private apiservice: ApiService ) { }

  resolve(route: ActivatedRouteSnapshot): Observable<any> {
    return this.apiservice.getProductTable('/api/products-columns');
  }
}

And the updated component

import { ActivatedRoute} from '@angular/router';

@Component({
  selector: 'app-new-product-general',
  templateUrl: './new-product-general.component.html',
  styleUrls: ['./new-product-general.component.scss']
})
export class NewProductGeneralComponent implements OnInit, OnDestroy {
  productTitles: [];
  productDescFormGroup: FormGroup;
  group = {};

  constructor(
    private apiservice: ApiService,
    private route: ActivatedRoute
  ) {}

  getProductColumns() {
    this.route.data
      .subscribe( res =>  {
        this.productTitles = res.productTitles;
        for(const k in this.productTitles) {
          this.group[k] = new FormControl('');
        }
      });

  }

  ngOnInit() {
    this.getProductColumns();
    this.productDescFormGroup = new FormGroup(this.group);
  }
mr_j
  • 125
  • 1
  • 15