Eric Cooper
Eric Cooper

Reputation: 11

Dynamic Angular 5 Nested Reactive Forms

I am currently using Angular Reactive forms for a project - it is a dynamic form that cannot really be modeled since properties on it will change overtime. Right now it is a highly nested form that is built out containing as much as 4-5 levels deep.

Right now I have a main/outer FormGroup, that contains a FormArray of 'Scripts' that has properties and an FormArray of 'Questions'. Questions has properties with a FormArray of 'Fields'. Fields has properties as well as another FormArray of Options for those fields. Not all 'Fields' will have options such as single-line-text, but drop-down field would.

It gets a Document object from CosmosDB and iterates through this and basically builds the FormGroup out... My question is because this seems very messy, and I was curious to know if there was a better way to achieve this.

Here is a Document sample

"ScriptType": "Script", "Questions": [ { "Question": "What is the year, make and model of the vehicle your calling about?", "Type": "question", "Text": "", "Fields": [ { "PropertyName": "VehicleYear", "Label": "Year", "IsRequired": false, "Type": "drop-down", "HasOptions": false, "Options": [2001, 2002, 2003, ...] }, { "PropertyName": "VehicleMake", "Label": "Make", "IsRequired": false, "Type": "single-line-text", "HasOptions": false, "Options": [] }

Below is the Angular component that currently initializes the form...

initScript(script) {
const scriptGroup = this.fb.group({
  ScriptID: script.ScriptID || '',
  ScriptType: script.ScriptType,
  ScriptName: script.ScriptName,
  ScriptText: script.ScriptText,
  Questions: this.fb.array([])
});
const scriptControl = scriptGroup.get('Questions') as FormArray;
script.Questions.forEach(element => {
  scriptControl.push(this.initQuestion(element));
});
return scriptGroup;
}

initQuestion(script) {
const questionGroup = this.fb.group({
  Question: script.Question || '',
  Type: script.Type || '',
  Fields: this.fb.array([script.Fields] || []),
  IsVisible: script.IsVisible || true,
  Rules: [script.Rules] || []
});

const fieldControl = questionGroup.get('Fields') as FormArray;
script.Fields.forEach(element => {
  fieldControl.push(this.initField(element));
});

return questionGroup;

initField(script) {
return this.fb.group({
  PopertyName: script.PropertyName || '',
  PropertyName: script.PropertyName || '',
  Label: script.Label || '',
  Type: script.Type || '',
  Options: [script.Options] || []
});
}

There maybe hundreds of these over time so accessing these controls on the front end is somewhat cumbersome being so nested as well. Also, the response to these 'Questions' also needs to be saved as well once a new form is submitted. If anyone has any suggestions please let me know! Thanks

Upvotes: 1

Views: 1589

Answers (1)

lubo08
lubo08

Reputation: 315

OK not sure if fully understand but see here example how dynamically create those fields. You could also generate them based on JSON loaded from back-end.

https://stackblitz.com/edit/angular-reactive-form-sobsoft

Upvotes: 1

Related Questions