0

I'm trying to build a test questionnaire from a json response. In console I get errors of 'Cannot read property 'Title' of undefined' because it seems like it wants to string interpolate before I get the response.

My code looks like this so far:

component.ts:

export class QuestionComponent implements OnInit {
  jsonQuestionnaire: Questionnaire;

  constructor(private http: HttpClient) { }

  ngOnInit() {
    console.log(this.jsonQuestionnaire);
    // Make the HTTP request:
    this.http.get('/assets/equestion.json').subscribe(data =>  {
    //   // Read the result field from the JSON response.
      this.jsonQuestionnaire = data as Questionnaire;
      console.log(this.jsonQuestionnaire);
      console.log(this.jsonQuestionnaire.Title);
      }
    );
  }
}

questionnaire.model.ts:

export interface Questionnaire {
  GuestName: string;
  QuestionnaireClose: boolean;
  QuestionnaireCompleted: boolean;
  Sections: Section[];
  Title: string;
  WelcomeText: string;
}

export interface Section {
  SectionName: string;
  SectionId: number;
  Questions: Question[];
}

export interface Question {
  AnswerReqired: boolean;
  Answers: Answer[];
  QuestionID: number;
  QuestionName: string;
  QuestionType: string;
}

export interface Answer {
  AnswerID: number;
  AnswerName: string;
}

and my html:

<div class="container">
  <div class="row">
    <div class="col-xs-12">
      <h1>{{jsonQuestionnaire.Title}}</h1>
      <p>{{jsonQuestionnaire.WelcomeText}}</p>
      <div *ngFor="let section of jsonQuestionnaire.Sections; let j = index">
        <br>
        <p>{{section[j].SectionName}}</p>
      </div>

    </div>
  </div>
</div>

Could anyone point me in the right direction what I got to fix? If I log all the properties I get as a response I do that without a problem. So how to delay the string interpolation?

Best regards, Aghi

Aghi
  • 119
  • 3
  • 13

2 Answers2

1

What you can do is, also have a boolean in your class. Set the boolean to false, by default, and when you get your response, set the boolean to true. Something like this:

export class QuestionComponent implements OnInit {
  jsonQuestionnaire: Questionnaire;
  isData: Boolean;

  constructor(private http: HttpClient) { 
     this.isData = false;
  }

  ngOnInit() {
    console.log(this.jsonQuestionnaire);
    // Make the HTTP request:
    this.http.get('/assets/equestion.json').subscribe(data =>  {
    //   // Read the result field from the JSON response.
      this.jsonQuestionnaire = data as Questionnaire;
      this.isData = true;
      console.log(this.jsonQuestionnaire);
      console.log(this.jsonQuestionnaire.Title);
      }
    );
  }
}

Now in your template, place an *ngIf on the desired output. Something like this:

<div class="container">
  <div class="row">
    <div class="col-xs-12" *ngIf="isData">
      <h1>{{jsonQuestionnaire.Title}}</h1>
      <p>{{jsonQuestionnaire.WelcomeText}}</p>
      <div *ngFor="let section of jsonQuestionnaire.Sections; let j = index">
        <br>
        <p>{{section[j].SectionName}}</p>
      </div>

    </div>
  </div>
</div>

That's it. Your div will be presented only when the data from your JSON is available.

Hence it won't show any errors.

Try it and let me know.

Vinod Bhavnani
  • 2,185
  • 1
  • 16
  • 19
  • Thank you. Your solution works in a similiar way than the above poster. I've upvoted it. – Aghi Jan 12 '18 at 12:34
1

You can either add a *ngIf to your HTML:

<div class="container">
  <div class="row" *ngIf="jsonQuestionnaire">
    <div class="col-xs-12">
      <h1>{{jsonQuestionnaire.Title}}</h1>
      <p>{{jsonQuestionnaire.WelcomeText}}</p>
      <div *ngFor="let section of jsonQuestionnaire.Sections; let j = index">
        <br>
        <p>{{section[j].SectionName}}</p>
      </div>
    </div>
  </div>
</div>

or add an safe navigation operator to you *ngFor:

<div class="container">
  <div class="row">
    <div class="col-xs-12">
      <h1>{{jsonQuestionnaire.Title}}</h1>
      <p>{{jsonQuestionnaire.WelcomeText}}</p>
      <div *ngFor="let section of jsonQuestionnaire?.Sections; let j = index">
        <br>
        <p>{{section[j].SectionName}}</p>
      </div>
    </div>
  </div>
</div>
chris vietor
  • 2,050
  • 1
  • 20
  • 29