Search code examples
angulartypescriptdependency-injectionangular-servicesangular2-databinding

How do I get a string value from service in an Angular component?


I am trying to get the value of a string variable explanationText from my QuizService to display in my di-quiz component template using data-binding. console.log is showing undefined for explanationText and data-binding to the template isn't displaying anything for explanationText when an answer is selected. Please see: https://stackblitz.com/edit/angular-9-quiz-app

Any idea why this is not working? Please can you help. Thank you!

In my quiz.service.ts file, I have:

@Injectable({providedIn: 'root'}) {
  export class QuizService {
  explanationText: string;
  ...

  setExplanationAndCorrectAnswerMessages() {
    this.question = this.getQuestion;
    if (this.question) {
      if (this.correctAnswers.length === 1) {
        this.explanation = ' is correct because ' + this.question.explanation + '.';
      }
      if (this.correctAnswers.length > 1) {
        this.explanation = ' are correct because ' + this.question.explanation + '.';
      }
    }

    if (this.correctAnswers && this.correctAnswers.length === 1) {
      const correctAnswersText = this.correctAnswers[0];
      this.explanationText = 'Option ' + correctAnswersText + this.explanation;
      console.log(this.explanationText);
      this.correctAnswerMessage = 'The correct answer is Option ' + this.correctAnswers[0] + '.';
      console.log(this.correctAnswerMessage);
    }
    if (this.correctAnswers && this.correctAnswers.length > 1) {
      if (this.correctAnswers[0] && this.correctAnswers[1]) {
        const correctAnswersText = this.correctAnswers[0] + ' and ' + this.correctAnswers[1];
        this.explanationText = 'Options ' + correctAnswersText + this.explanation;
        console.log(this.explanationText);
        this.correctAnswerMessage = 'The correct answers are Options ' + correctAnswersText + '.';
        console.log(this.correctAnswerMessage);
      }
      ...
    }
  }

In my di-quiz.component.ts, I have a getter/setter and constructor as follows:

get explanation(): string { return this.quizService.explanationText; };
@Input() set explanation(value: string) { this.explanationText = value; };

constructor(private quizService: QuizService,
            private timerService: TimerService,
            private route: ActivatedRoute) {
  this.explanationText = this.explanation;
  console.log("ExpTxt: " + this.explanationText);
}

and in my di-quiz.component.html, I have

<section id="question" [class.answered]="answer">
  <span *ngIf="!answer">{{ question?.questionText }}</span>
  <span *ngIf="answer">{{ explanationText }}</span>
</section>

Solution

  • I check your stackblitz code and found the issue. Its because you are registering your QuizService in DependencyInjectionQuizComponent and QuestionComponent, which creates multiple instace.

    So when question component fires setExplanationAndCorrectAnswerMessages it update explanationText in different instance but your DIQuizComponent expect from different instance.

    To fix this you have to remove QuizService from QuestionComponent providers.

    I have forked and updated the code. Here is the link