title: Generating Dynamic Form from JSON file with infinite tiers of nesting
body: <p>I created a mechanism for my questionnaires that I'm making into an <code>Angular Form</code>.  So far I have everything working the way I want which you can take a look at here <a href="https://plnkr.co/edit/nBpriDOgC88Fo2WMpM6A?p=preview" rel="nofollow noreferrer">https://plnkr.co/edit/nBpriDOgC88Fo2WMpM6A?p=preview</a></p>
  
  <p>So far all I've seen in regards to creating dynamic forms is pretty simple and strait forward with a couple of fields and no conditional situations, meanwhile I have groups of questions nested 3-4 tiers deep and fields in my database used strictly for logical purposes.</p>
  
  <p>I studied the <code>Dynamic Forms</code> docs on <code>Angular.io</code> again particularly this chunk of code
      toFormGroup(questions: QuestionBase[] ) {
          let group: any = {};</p>
  
  <pre><code>    questions.forEach(question =&gt; {
        group[question.key] =
            question.required ? new FormControl(question.value || '', Validators.required): new FormControl(question.value || '');
      });
      return new FormGroup(group);
    }
  </code></pre>
  
  <p>As they're using it to bind their mock data  I figured this would be a good starting place.</p>
  
  <p>This is how I've shaped my data model</p>
  
  <pre><code>export class QuestionPrimative {
      question    : string;
      id          : string;
      name        : string;
      ctrlName?   : string;
      lowExtreme? : string;
      hiExtreme?  : string;
      template    : string;
  }
  
  export class Answer {
      answer      : string;
      id          : string;
      trigger?    : string;
      formctrl?   : string;
  }
  
  export class QuestionBase extends QuestionPrimative {
      answers?    : Answer[];
  }
  
  export class MicroQuestions {
      activate    : string;
      questions   : Question[];
      childgroup  : string;
  }
  
  export class Question extends QuestionBase {
      micros?     : MicroQuestions[];
  }
  
  export class QuestionSection {
      name        : string;
      questions   : Question[];
  }
  
  export class QuestionnaireBody{
      sections: QuestionSection[];
  }
  </code></pre>
  
  <p>The rationality behind the shape of my data goes as follows</p>
  
  <pre><code>//The data when it iterates into Component
  question    : string;           // the question to be asked
  id          : string;           // id attribute for HTML
  name        : string;           // name attribute for HTML
  ctrlName?   : string;           // form control name
  template    : string;           // matches *ngIf on appropriate chunk of HTML
  answers?    : Answer[];         // available answers if multiple choice
  lowExtreme? : string;           // low extreme if question involves rating
  hiExtreme?  : string;           // hi extreme for rating
  micros?     : MicroQuestions[]; // if more questions are available
  
  //if answers are available.....
  answer      : string;           // the answer
  id          : string;           // id attribute for HTML
  trigger?    : string;           // used to trigger another tier of questions
  formctrl?   : string;           // if element needs to be a form control
  
  //if there is another tier of questions ......
  activate?   : string;           // matches with the 'trigger' in the answer to know to load
  questions?  : QuestionBase[];   // the next tier of questions
  </code></pre>
  
  <p>I'm attempting to do build the entire form inside of my service file which looks like this</p>
  
  <pre><code>import { Injectable, OnInit }       from '@angular/core';
  
  import { FormBuilder, FormControl,
           FormGroup, FormArray }     from '@angular/forms';
  
  import { QuestionSection }          from '../../data-types/question-section';
  import { Question }                 from '../../data-types/question';
  
  import { Response, Http }           from '@angular/http';
  import { Observable }               from 'rxjs/observable';
  
  import 'rxjs/add/operator/map';
  import 'rxjs/add/operator/catch';
  
  
  
  @Injectable()
  
  export class QuestionService implements OnInit {
  
      QuestionnaireData: any;
      QuestinnaireLoad: FormGroup;
  
  
  
      constructor(private http: Http, private fbuild: FormBuilder){
          this.QuestionnaireLoad = this.fbuild.group({
              sections: this.fbuild.array(this.buildSections(data: this.QuestionnaireData.sections) ||'');
          });
      }
  
      ngOnInit(){ this.getData(); }
  
      getData() {
          this.QuestionnaireData = this.http.get('app/questionnaire/questions.json')
          .map(res =&gt; res.json())
  
          return this.QuestionnaireData;
      }
  
  
      buildSections(data){
          let group: any = {};
  
          data.forEach(section =&gt;{
              group[section.name]         = name      : section ? section.name: '';
              group[section.questions]    = questions : new FormArray(this.buildQuestionnaire(quest: section.questions) ||'');
          });
  
          return new FormGroup(group);
      }
  
      buildQuestion(quest){
          let group: any = {};
  
          sect.forEach(ques =&gt;{
              group[ques.question]    = question  : ques ? ques.question: '';
              group[ques.id]          = id        : ques ? ques.id: '';
              group[ques.name]        = name      : ques ? ques.name: '';
              group[ques.ctrlName]    = ctrlName  : ques ? ques.ctrlName: '';
              group[ques.template]    = template  : ques ? ques.template: '';
              group[ques.lowExtreme]  = lowExtreme: ques ? ques.hiExtreme: '';
              group[ques.hiExtreme]   = hiExtreme : ques ? ques.lowExtreme: '';
              group[ques.answers]     = answers   : new FormArray(this.buildAnswers(answ: ques.answers) ||'');
              group[ques.micros]      = micros: new FormGroup(this.buildMicros(mic: ques.micros) ||'');
          });
  
          return new FormGroup(group);
      }
  
      buildAnswer(answ){
          let group:any = {};
  
          answ.forEach(item =&gt;{
              group[item.answer]  = answer  : item ? item.answer: '';
              group[item.id]      = id      : item ? item.id: '';
              group[item.trigger] = trigger : item ? item.trigger: '';
              group[item.ctrlName]= ctrlName: item ? item.ctrlName: '';
          });
  
          return new FormGroup(group);
      }
  
      buildMicros(mic){
          let group: any = {};
  
          mic.forEach(micro =&gt;{
              group[micro.activate]  = activate  : micro ? micro.activate: '';
              group[micro.childGroup]= childGroup: micro ? micro.childGroup: '';
              group[micro.questions]= new FormArray(this.buildQuestion(quest: micro.questions) || '');
          });
  
          return new FormGroup(group);
      }
  }
  </code></pre>
  
  <p>So far I'm getting an error telling me data isn't defined, I'm not even sure if this is what I should even be trying to do.  Some of the fields I want to simply be fields, rather than controls, which is why I'm only making a few controls, groups and arrays here and there.  At the end of the day I want to be able to make any <code>.json</code> file shaped in the manner I outlined before and have everything automatically work itself out.  How can I go about doing this?</p>