0

I'm trying to get the dynamic forms example in https://angular.io/guide/dynamic-form working with metadata that's returned from a Django API I've set up.

https://plnkr.co/edit/Nks8fD?p=preview (copied from the generated one in the docs)

The Django API isn't available online at the moment, so I fake an API call in app/question.service.ts like this:

getQuestions(): Promise<QuestionBase[]> {
    return new Promise(resolve => {
        // Simulate server latency with 2 second delay
        setTimeout(() => resolve(this.getQuestionsOriginal()), 2000);
    });
}

this.getQuestionsOriginal() just returns an array of questions, like:

QuestionBase<any>[] = [
  new DropdownQuestion({
    key: 'brave',
    label: 'Bravery Rating',
    options: [
      {key: 'solid',  value: 'Solid'},
      {key: 'great',  value: 'Great'},
      {key: 'good',   value: 'Good'},
      {key: 'unproven', value: 'Unproven'}
    ],
    order: 3
  }),
  new TextboxQuestion({
    key: 'firstName',
    label: 'First name',
    value: 'Bombasto',
    required: true,
    order: 1
  }),
  new TextboxQuestion({
    key: 'emailAddress',
    label: 'Email',
    type: 'email',
    order: 2
  })
 ];

Then in the constructor of app/app.component.ts I've tried to retrieve the questions and assign them to a local variable this.questions, which is bound into the template like this:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Job Application for Heroes</h2>
      <dynamic-form [questions]="questions"></dynamic-form>
    </div>
  `,
  providers:  [QuestionService]
})
export class AppComponent implements OnInit {
  questions = Array();

  constructor(private service: QuestionService) {
    this.service.getQuestions((questions) => { 
        this.questions = questions;
    });  
  }
}

But this doesn't work - it gives an error "Cannot read property 'valid' of undefined", which suggests that this.questions is not getting populated (as the form is checking for valid form elements). And in fact if I add an ngOnInit and console.log(this.questions), I can see it's empty. How do I populate this.questions?

I have also tried running this.service.getQuestions((questions) => { this.questions = questions; }); in the ngOnInit, with the same results. How do I get the bound questions to update when the promise is resolved?

I have found a similar question on stackoverflow which was not resolved Setting Values From API for Angular 2 Dynamic Form the developer ended up generating the form questions when the user clicked a button to get around this issue. That's not an option for me, unfortunately.

rkian
  • 98
  • 2
  • 9

1 Answers1

2

Your questions is actually not undefined once the data comes through. Check this one: How do I return the response from an Observable/http/async call in angular2? and the accepted answer to understand as why your console.log prints undefined here:

service.getQuestions().then(questions => this.questions = questions);
console.log(this.questions);

But over to your actual question. Since this is an async operation, it takes some while for the response to come through. Before that angular is trying to display the template. So we can set a condition that the DynamicFormComponent is not to be displayed until questions is populated. So in the AppComponent do:

<dynamic-form *ngIf="questions" [questions]="questions"></dynamic-form>

and that will solve your issue! :)

Your plunker: https://plnkr.co/edit/h2X1Ck?p=preview

AT82
  • 71,416
  • 24
  • 140
  • 167
  • For anyone still struggling with this issue as the tutorial changed, here the current working version! https://angular-iej9fp.stackblitz.io – Philip Gierszal May 14 '21 at 10:36