Making the Guide Interactive

Introduction: Making the Guide Interactive

Welcome back! In the last lesson, you built a step-by-step cooking guide page using a TypeScript component and its template. You set up the structure, added navigation buttons, and connected styles and logic within the component. That was a great start, but the page is still static — it doesn’t respond to user actions yet.

In this lesson, you will learn how to use TypeScript to make the guide page interactive within your component. By the end, your users will be able to move through recipe steps, hear instructions read aloud, use timers, and see updates instantly — all without reloading the page. This will make your cooking helper much more user-friendly and fun to use.

Quick Recap: The Static Guide Page

Let’s quickly remind ourselves what you built in the previous lesson. You created a Angular component with a template that shows the recipe name, the current step, and navigation buttons like Previous and Next. The template might look like this:

<!-- guide.component.html -->

<section class="guide-container">
  <h1 id="recipe-name">{{ recipeName }}</h1>

  <div class="step-box">
    <p id="current-step-text">{{ currentStepText }}</p>
    <div class="step-controls">
      <button id="prev-step" type="button" (click)="onPrevStep()" [disabled]="loading || currentIndex === 0 || completed">← Prev</button>
      <button id="play-tts" type="button" (click)="playCurrentTts()" [disabled]="loading || completed || !steps.length">🔊 Read Step</button>
      <button id="next-step" type="button" (click)="onNextStep()" [disabled]="loading || completed || !steps.length">
        {{ currentIndex === steps.length - 1 ? 'Finish' : 'Next →' }}
      </button>
    </div>
    <p class="keyboard-hint">
      <small>Tip: Use <kbd>←</kbd> <kbd>→</kbd> arrows to navigate and <kbd>Space</kbd> to hear the step.</small>
    </p>
    @if (error) { <p class="error">{{ error }}</p> }
  </div>

  @if (timerVisible) {
    <div id="timer-box" class="timer-box">
      <p><strong>Timer: </strong> <span id="timer-countdown">{{ timerRemaining }}</span> seconds remaining</p>
    </div>
  }
</section>

At this point, your component class defines the properties, but the logic for interactivity is not yet implemented.

Fetching and Showing Recipe Data

The first thing we want to do is load the recipe name and steps from the server and display them on the page. In a Angular component, you typically fetch data in the class and bind it to the template using properties.

Here’s how you can do it:

// guide.component.ts

import { Component, OnInit } from '@angular/core';
import { ApiService } from '../../services/api.service';

@Component({
  selector: 'app-guide',
  templateUrl: './guide.component.html',
  styleUrls: ['./guide.component.css']
})
export class GuideComponent {
  recipeName = 'Loading...';
  steps: string[] = [];
  currentIndex = 0;
  loading = true;
  error = '';

  constructor(private api: ApiService) { this.loadSteps(); }

  private loadSteps(): void {
    this.api.getRecipeSteps(/* recipeId */).subscribe({
      next: (data) => {
        this.recipeName = data.name;
        this.steps = data.steps;
        this.loading = false;
      },
      error: () => {
        this.error = 'Failed to load recipe steps.';
        this.loading = false;
      }
    });
  }

  get currentStepText(): string {
    return this.steps[this.currentIndex] ?? 'Fetching steps...';
  }
}

Explanation:

  • The constructor loads the steps when the component is initialized.
  • The loadSteps method fetches the steps from the server using an injected ApiService.
  • The template binds to recipeName and currentStepText to display the data.
  • If there’s an error, the error property can be used to show a message in the template.

Output:
When the component loads, you should see the recipe name and the first step appear.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal