0

I have been trying to sort this out for a while now and could definitely use some help. I am trying to display the question I got from the server and stored locally. But When i try to display the question that i got it gives me the following error:

Cannot read property 'question' of undefined

Here's my HTML

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Questionnaire</title>
</head>
<body>
<div class="container" id="Question" align="center">
 <h2 [innerHTML] = "q.question"></h2>
</div> 


</body>
</html>

Here's typescript that is for sure returning values because i can log them and so I checked:

@Component({
  selector: 'app-new-questionnaire',
  templateUrl: './new-questionnaire.component.html',
  styleUrls: ['./new-questionnaire.component.css'],
  providers: [NewServerRequestsService]
})

export class NewQuestionnaireComponent implements OnInit {



  q: any;
  sub: any;
  id: number;
  cQuestion: number;
  score: number;
  qNumber: number;

  constructor(private serverService: NewServerRequestsService, private 
route: ActivatedRoute, private router: Router){} 


  static questionTime = performance.now();  
  onload()
  {
    console.log(NewQuestionnaireComponent.questionTime);
    // this.ButtonClicks();    
  }

  ngOnInit() {
    this.sub = this.route.params.subscribe(params => {
      // (+) converts string 'id' to a number
      // fetch the file and get next Question
      this.id = +params['id'];

      if (localStorage.getItem('q') !== null) {
        var data = JSON.parse(localStorage.getItem('q'))
        this.qNumber = parseInt(localStorage.getItem('qNumber'))
        this.q = data.results[this.id - 1]
      } else {
        this.serverService.getQuestion()
        var data = JSON.parse(localStorage.getItem('q'))
        this.qNumber = parseInt(localStorage.getItem('qNumber'))
        this.q = data.results[this.id - 1]
      }

    });
  }

    }

  }

Here's the service:

@Injectable()
export class NewServerRequestsService {

  constructor(private http: Http) { }

  getQuestion()
  {
    return this.http.get("https://opentdb.com/api.php?amount=30")
    .map(res => res.json()).subscribe(
    data => {
        // shuffle questions
        for (var i = 0; i < data.results.length - 1; i++) {
            var j = i + Math.floor(Math.random() * (data.results.length - 
i));

            var temp = data.results[j];
            data[j] = data.results[i];

            data[j].incorrect_answers.push(data[j].correct_answer)

            data[i] = temp;

        }
        localStorage.setItem("q", JSON.stringify(data))
        localStorage.setItem("qNumber", JSON.stringify(data.length))
    },
    err => console.error(err)
    )

}

}

Here's where the data gets fetched:

  @Component({
  selector: 'home',
  templateUrl: 'home.component.html',
  providers: [NewServerRequestsService]
})

export class HomeComponent implements OnInit, OnDestroy {

  constructor(private QuizService: NewServerRequestsService, private route: 
ActivatedRoute, private router: Router) {

  }

  ngOnInit() {
    this.QuizService.getQuestion();
  }
  ngOnDestroy() { }

}
  • 1
    Try stripping out all non-essential code to provide a minimal example that reproduces your problem. That way people will more likely try to help you, and the question will be more helpful to others with a similar problem. – dskrvk Nov 26 '17 at 17:03
  • 1
    You've (at least) got some trouble with asynchronicity, both in template and TS. when calling `this.serverService.getQuestion()` you cannot be sure that the data is set in localStorage when you are fetching it: `var data = JSON.parse(localStorage.getItem('q'))` in your `else`. I'm 99% sure that the data isn't there. Please read this: https://stackoverflow.com/questions/43055706/how-do-i-return-the-response-from-an-observable-http-async-call-in-angular2 and this: https://stackoverflow.com/questions/34734671/observable-type-error-cannot-read-property-of-undefined to understand asynchronicity. – AT82 Nov 26 '17 at 17:04
  • @dskrvk Thanks for letting me know. I've stripped the unnecessary stuff. – Chirag Bhardwaj Nov 26 '17 at 17:15
  • @AJT_82 Ive made some edits. Please go through the same. – Chirag Bhardwaj Nov 26 '17 at 17:16
  • @AJT_82 is correct, it is an issue with asynchronicity. When you render the dom, `q` is not yet defined. – ppovoski Nov 26 '17 at 17:32
  • I am going through the links. Thanks for helping. Will post when i make all the adjustments. :) – Chirag Bhardwaj Nov 26 '17 at 17:33
  • @AJT_82 Even though i have gone through the links i still am not being able to get it done and despite trying promises and observables im getting the same error. Please help me out – Chirag Bhardwaj Nov 26 '17 at 20:30

2 Answers2

1

this error occurs because q is undefined when rendering the view , try using safe navigation by using ? :

<h2 [innerHTML] = "q?.question"></h2>
Mohamed Ali RACHID
  • 3,245
  • 11
  • 22
0

initialize q: any = {} if it's an object, [] if array ;) tell me now what console.log(q) show

Check q in your ts or on your html <h2 *ngIf="q" ...

andrea06590
  • 1,259
  • 3
  • 10
  • 22
  • it says undefined – Chirag Bhardwaj Nov 26 '17 at 20:03
  • Ok so you never get or change the value in your component that fetch the data, when you get them, it is asynchronous so you must verify if it exists & create an empty objet you can show until you get the data ;) Then try q = this.QuizService.getQuestion(); si that you can use q and display it :) – andrea06590 Nov 26 '17 at 20:51