5
\$\begingroup\$

I implements big reactive form on angular5. This form get data from JSON. I use formBuilder and several nested formGroups.

Every field have default value before rendering form. In console output form values after submit form.

CSS design is very simple.

Live demo here.

js:

  formData = {
    'Информация из КХД': {
      Марка: {
        type: 'input',
        value: 'qwerty',
      },
    'Модель': {
        type: 'select',
        value: ['wqeqwewq', 'sadasdasdda', 'xcvxcxcvxcv',],
        selected: 1,
      },
      'Год выпуска': {
        type: 'input',
        value: '',
      },
    },
    'Общая информация': {
      'ПТС': {
        type: 'input',
        value: 'qwerty',
      },
      'Пробег': {
        type: 'select',
        value: ['tgtrgrt', 'fdvdfvdf', 'csdcscsc',],
        selected: 2,
      },
      'Тип кузова': {
        type: 'select',
        value: ['sdv', '544564564', 'yjyujuyj',],
        selected: 0,
      },
    },
    // and more, more, more...
  }

  form: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit() {
    this.form = this.fb.group(
      this.createForm(Object.keys(this.formData))
    );
  }

  createForm(fields) {
    const result = {};
    fields.forEach(field => {
      const fields = Object.keys(this.formData[field])
      result[field] = this.fb.group(this.createSubForm(field, fields));
    });
    return result;
  }

  createSubForm(field, fields) {
    const result = {};
    fields.forEach(f => {
      let fd = this.formData[field][f];
      if (fd.type === 'select') {
        result[f] = new FormControl(fd.value[fd.selected]);
      } else if (fd.type === 'input') {
        result[f] = new FormControl(fd.value);
      }      
    });
    return result;
  }

  getKeys() {
    return Object.keys(this.form.controls);
  }

  getSubKeys(key) {
    const subControls = this.form.get(key).value;
    return Object.keys(subControls);
  }

  onSubmit() {
    console.log('form submitted', this.form.value);
  }

html:

<form class="form" [formGroup]="form" (ngSubmit)="onSubmit()">
  <div class="key" *ngFor="let key of getKeys()">
    <h1 class="head">{{key}}</h1>

    <div class="subKey" *ngFor="let subKey of getSubKeys(key)" [formGroupName]="key">
      <label>{{subKey}}</label>

      <input type="text" [formControlName]="subKey" *ngIf="formData[key][subKey].type === 'input'">

      <select [formControlName]="subKey" *ngIf="formData[key][subKey].type === 'select'">
        <option 
          *ngFor="let item of formData[key][subKey].value; let i = index" 
          [value]="item">
          {{ item }}
        </option>
      </select>
    </div> 
  </div>  

  <button class="submit" type="submit">Submit</button>
</form>

scss:

.head {
    font-weight: bold;
    text-decoration: underline;
    width: 100%;
    margin-bottom: 20px;
}

.key {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 30px;

    .subKey {
        width: 47%;
        display: block;
        margin-bottom: 15px;

        >* {
            width: 100%;
        }
    }
}
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

It's an unusual approach, it's very cryptic and as a result will be a bad maintenance of the code in the future, if in the future you wanna add some custom validators, style or add some dependent validators or other things will became a chimera this component, definetly will kill productivity on quick prototyping. If you wanna handle a big bulks of forms, i suggest you to look at using a dynamic form.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.