2025 Angular 19 Tutorial: Build a Movies App with Angular 19, HttpClient and Tailwind

2025 Angular 19 Tutorial: Build a Movies App with Angular 19, HttpClient and Tailwind

In this tutorial, we'll be using Angular 19, the latest version of Angular, the popular platform for building front-end web applications with TypeScript. The latest version, released on November 19, 2024, brings a set of new features and enhancements that we will leverage to build a robust movies application in 2025.

Before proceeding, here’s a quick rundown of what’s new in Angular 19:

What's New in Angular 19 (2025):

  • Improved Signal API: Enhanced reactivity model with better performance and DX.
  • View Transitions API: Smooth animations and transitions between pages.
  • Standalone API Enhancements: More flexible and modular standalone components.
  • New Server-Side Rendering (SSR) Improvements: Faster hydration and improved SEO.
  • Better TypeScript Integration: Full support for TypeScript 5.x features.
  • RxJS 8 Support: Optimized Observables with better tree-shaking.
  • Enhanced Build Performance: Faster compilation times with esbuild optimizations.
  • Improved Forms Module: Enhanced reactive forms and validation features.
  • Angular CLI Upgrades: More automation and improved developer experience.
  • Experimental Signals Integration: A more declarative approach to state management.

With these improvements, Angular 19 makes front-end development faster, more efficient, and easier to maintain.

This Article is Part of the Angular 19: From Zero to Hero in 2025 Series

This tutorial is part of the Angular 19: From Zero to Hero in 2025 series, a comprehensive guide designed to take you from beginner to expert in Angular development. Each article in this series builds upon the previous one, introducing new concepts and best practices to help you master modern web development with Angular 19.

Stay tuned for more tutorials covering advanced topics like state management, server-side rendering (SSR), and performance optimizations to further enhance your Angular skills in 2025 and beyond.

Why Building Web Apps with Angular 19 and Tailwind in 2025?

Building an app with Angular 19 in 2025 is a great choice due to its cutting-edge performance optimizations, improved developer experience, and future-proof architecture. The latest advancements in Signals API, View Transitions, and enhanced SSR capabilities make it ideal for building fast, interactive, and scalable web applications. Additionally, RxJS 8 support, better TypeScript integration, and enhanced CLI tools streamline development, reducing complexity and improving maintainability. Choosing Angular 19 in 2025 ensures you are working with the latest security patches, best practices, and modern web technologies.

Using Tailwind CSS with Angular 19 in 2025 provides several key benefits:

  • Faster Development: Utility-first approach enables rapid styling without writing custom CSS.
  • Optimized Performance: Automatically removes unused styles with JIT (Just-In-Time) compilation.
  • Scalability: Works well with Angular’s modular architecture, making styles easy to maintain.
  • Responsive Design: Built-in responsive utilities for mobile-first development.
  • Consistent UI: Predefined styles ensure design consistency across components.
  • Dark Mode & Theming: Easily customizable themes and dark mode support.
  • Seamless Integration: Works effortlessly with Angular’s component-based structure.

By combining Angular 19’s modern features with Tailwind CSS, developers can build highly responsive and maintainable applications in 2025.

What We'll Building in this Tutorial?

We'll be building a movie application with Angular 19 and an API, showcasing different concepts such as working with standalone components to create modular and reusable UI elements, services to handle business logic and data sharing, consuming a REST API with HttpClient to fetch and display movie data dynamically, Observables to manage asynchronous data streams efficiently, infinite scrolling to improve user experience by loading data dynamically as the user scrolls, and playing videos to showcase movie trailers. We'll also cover the use of the async pipe to handle observable data efficiently and various other pipes like the date and currency pipes for formatting data dynamically. By the end of this 2025 Angular 19 tutorial, you will have a solid understanding of how to build dynamic and interactive web applications using Angular 19. We'll also be using Tailwind CSS for styling our UI.

Our 2025 Angular 19 movies application will have the following features:

  1. Three pages: Home, Movies, and Show Movie pages.
  2. Navbar and footer standalone components.
  3. Three sections for movies: Popular, Top Rated, and Now Playing.
  4. Image slider: A movies slider.
  5. Scrolling functionality: Buttons to navigate through movie lists.
  6. Movie cards: Each movie will be displayed in a card format containing the title, release date, and rating.
  7. API Integration: Get movie data from an external API.
  8. Responsive UI: A clean and responsive user interface using Tailwind CSS.
  9. Infinite scrolling.

Through the features we implemented, you'll gain hands-on experience in several key areas of modern Angular development:

  • Component-Based Architecture: Understanding how to structure an Angular app using standalone components for better reusability and maintainability.
  • Reactivity: Using Angular's  Observables.
  • API Integration & Data Fetching: Using Angular's HttpClient to consume and display real-time data from an external API.
  • Routing & Navigation: Implementing Angular’s RouterModule to navigate between different pages seamlessly.
  • UI/UX Enhancements: Leveraging Tailwind CSS for a responsive and modern UI, along with smooth animations.
  • Infinite Scrolling & Performance Optimization: Dynamically loading data as the user scrolls, improving both performance and user experience.
  • Async Data Handling: Using the async pipe and RxJS operators to efficiently manage asynchronous operations.

By mastering these concepts, you'll develop a strong foundation in building scalable and interactive web applications with Angular 19 in 2025.

Let's start with the home page. Here is the top of the home page we'll be building in our angular 19 tutorial: angular 19 tutorial

The top of the home page contains a movies slider that slides a set of movies displaying their images, titles, descriptions and release data.

Here is the bottom of the home page:

angular 19 tutorial

It contains three sections: Popular, Top and Now Playing sections. When we click on the buttons at the left and right sides we scroll horizontally through the movies. Each movie is displayed in a card format containing the title, release date and rating.

The second page is the movies pages with infinite scrolling where we scroll vertically through movies. Each movie is displayed in a card format containing the title, release date and rating:

angular 19 tutorial When the user scrolls down to the bottom, more movies will be fetched by Angular HttpClient and displayed.

The last page is the Show Movie page that looks like this on top:

angular 19 tutorial

It contains images of the movie plus the title and overview and the actors. It also contains the Play Now button the plays a trailer video of the movie.

At the bottom, it looks like this:

angular 19 tutorial

It contains an horizontally scrolling standalone component of the similar movies.

All pages contains a navbar and footer. The navigation bar contains links to the home and movies pages.

Let's start our 2025 Angular 19 movies tutorial.


Angular 19 Tutorial: Installing Angular CLI v19 & Creating a Project

To start building our movies application with Angular 19, we need to first install the Angular CLI (Command Line Interface) version 19. The Angular CLI is a powerful tool that helps in automating various tasks when developing Angular applications, such as creating new projects, generating components, and running tests.

Step 1: Install Node.js and npm

Ensure you have Node.js and npm (Node Package Manager) installed on your system. You can download and install them from the official Node.js website. Once installed, you can verify the installation by running the following commands in your terminal:

node -v
npm -v

These commands should display the versions of Node.js and npm installed on your system.

Step 2: Install Angular CLI

To install Angular CLI v19, open your terminal and run the following command:

npm i --global @angular/cli

The --global flag installs the Angular CLI globally on your system, allowing you to use the ng command from anywhere.

Step 3: Verify the Installation

After the installation is complete, verify that Angular CLI v19 is installed by running:

ng version

This command will display the installed Angular CLI version along with other related package versions.


Creating a New Angular 19 Project

With Angular CLI installed, we can now create a new Angular 19 project for our 2025 movies application.

Step 1: Create a New Project

Run the following command to create a new Angular project named movies-app:

ng new movies-app

The CLI will prompt you to select various configuration options, such as which stylesheets format to use. For this Angular 19 tutorial, choose the following options:

? Which stylesheet format would you like to use? CSS
? Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? No

Step 2: Navigate to the Project Directory

After the project is created, navigate to the project directory:

cd movies-app

Angular 19 Tutorial: Configuring Tailwind CSS

Tailwind CSS is a utility-first CSS framework that allows you to build custom designs without leaving your HTML. In this section, we will configure Tailwind CSS in our Angular application to leverage its powerful styling capabilities.

Step 1: Install Tailwind CSS

First, we need to install Tailwind CSS along with PostCSS and Autoprefixer. Open your terminal and navigate to the root directory of your Angular project. Then, run the following commands:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

The npx tailwindcss init command creates a tailwind.config.js file, which is used to configure Tailwind CSS.

Step 2: Configure Tailwind CSS

Open tailwind.config.js and add the paths to all of your template files. Inside the content array, add:

"./src/**/*.{html,ts}",

This configuration tells Tailwind CSS to remove any unused styles in production by scanning all .html and .ts files in the src directory.

Step 3: Import Tailwind CSS

We need to import Tailwind CSS into our global styles file. Open the src/styles.css file and add the following lines:

@tailwind base;
@tailwind components;
@tailwind utilities;

These directives include Tailwind's base styles, component classes, and utility classes into your project.

Step 4: Test Tailwind CSS

To ensure that Tailwind CSS is working correctly, let's add some Tailwind classes to our app.component.html file. Open src/app/app.component.html and replace its content with the following:

<div class="flex w-full h-screen items-center justify-center bg-slate-600">
  <h1 class="text-3xl font-bold">Hello Tailwind!</h1>
</div>
<router-outlet></router-outlet>

This code snippet uses Tailwind utility classes to style the page, setting a minimum height for the screen, centering content both vertically and horizontally, applying a background color, and styling the text.

Step 5: Start the Development Server

Now, start the development server to see the changes:

ng serve

Open your browser and navigate to http://localhost:4200/. You should see a styled page with the message "Hello Tailwind!".

angular 19 tutorial

At this point, we have successfully installed Angular CLI v19, created a new Angular project named movies-app and installed and configured Tailwind CSS in our Angular 19 application. We've also verified that Tailwind CSS is working by adding some utility classes to our app.component.html file. Tailwind CSS is now ready to be used for styling the rest of our movies application.

Next, we will proceed with building the core components and integrating the movies API to fetch and display movie data. Here's an overview of what we'll cover:

  1. Creating Components: We'll create reusable Angular standalone components for the navbar, footer, and movie cards.
  2. Setting Up Services: We'll set up an Angular service to handle API calls for fetching movie data.
  3. Building the Home Page: We'll build the home page, which includes a movie slider and sections for Popular, Top Rated, and Now Playing movies.
  4. Implementing the Movies Page: We'll implement the movies page with infinite scrolling to load more movies as the user scrolls down.
  5. Creating the Show Movie Page: We'll create a detailed view for individual movies.

In the next steps, we will start building the standalone components and services for our movies application, integrating it with an external API to fetch movie data, and adding the necessary functionality to display and interact with the movie data.

Adding & styling the navigation bar component with Tailwind CSS

To enhance the navigation experience in our movies application, we'll create a reusable standalone Navbar component. This component will be added to our main application component to ensure it appears on every page.

Using Angular CLI, generate a new standalone component called navbar:

ng g c components/navbar

This command creates the following files in the src/app/components/navbar directory:

  • navbar.component.ts
  • navbar.component.html
  • navbar.component.css
  • navbar.component.spec.ts

Next, we need to add the navbar component to the app standalone component. First, in the src/app/app.component.ts file, import NavbarComponent and add it the imports array:

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { NavbarComponent } from './components/navbar/navbar.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, NavbarComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent {
  title = 'moviesapp';
}

Next, in the src/app/app.component.html include the component:

<div class="bg-black">
  <app-navbar></app-navbar>
  <router-outlet></router-outlet>
</div>

Open the src/app/components/navbar/navbar.component.ts file and import the router module:

import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';

@Component({
  selector: 'app-navbar',
  standalone: true,
  imports: [RouterModule],
  templateUrl: './navbar.component.html',
  styleUrl: './navbar.component.css'
})
export class NavbarComponent {}

Next, we'll define the layout for our navigation bar. Open the src/app/components/navbar/navbar.component.html file and add the following HTML:

<nav class="fixed top-0 w-full h-12 flex bg-slate-700 text-white justify-between z-50">
  <div class="flex items-center gap-10 px-10">
    <img class="w-9" src="logo.svg" />
    <a routerLink="/">Home</a>
    <a routerLink="/movies">Movies</a>
  </div>
</nav>

This <nav> element creates a fixed navigation bar at the top of the viewport. The bar has a dark slate background and white text. It uses Flexbox for layout, ensuring the logo and navigation links are evenly spaced and centered vertically within the bar. The navigation bar remains on top of other content due to the z-50 z-index setting.

By structuring the <nav> element this way, we create a responsive and visually appealing navigation bar that enhances the user experience on our Angular application.

This is how it looks:

angular 19 tutorial

Just like we did with the navbar component, generate the footer component and include it in the app component below the router outlet:

<div class="bg-black">
  <app-navbar></app-navbar>
  <router-outlet></router-outlet>
  <app-footer></app-footer>
</div>

In the src/app/components/footer/footer.component.html add the following HTML code:

<footer>
  <p class="bg-slate-700 text-white text-center mt-20">
    Created by Techiediaries
  </p>
</footer>

Creating Angular 19 Routing Components

To build our movies application, we'll need different pages to display various sections like Home, Movies, and a detailed Show Movie page. We'll achieve this by creating routing components and setting up routes in Angular.

In the terminal, run the following commands:

ng g c pages/home
ng g c pages/movies
ng g c pages/show-movie

Open the src/app/app.routes.ts file and add the routes to different components:

import { Routes } from '@angular/router';
import { HomeComponent } from './pages/home/home.component';
import { MoviesComponent } from './pages/movies/movies.component';
import { ShowMovieComponent } from './pages/show-movie/show-movie.component';

export const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    pathMatch: 'full',
  },
  {
    path: 'movies',
    component: MoviesComponent,
  },
  {
    path: 'show-movie/:movieId',
    component: ShowMovieComponent,
  },
];

The routes array contains route configurations that define how different paths in our Angular application should be handled. Each route configuration specifies a path and the component that should be displayed when that path is accessed. Dynamic route parameters can also be used to create more flexible routes that handle varying data. With this route configuration, our application knows how to navigate to different views based on the URL.

The first route configuration specifies that when the root path ('') is accessed, the HomeComponent should be displayed. The pathMatch: 'full' ensures that the route matches only when the entire URL matches the empty string.

The second route configuration specifies that when the /movies path is accessed, the MoviesComponent should be displayed.

The last route configuration specifies a dynamic route parameter :movieId within the path /show-movie/:movieId. When a URL matching this pattern is accessed (e.g., /show-movie/123), the ShowMovieComponent is displayed. The movieId parameter can be accessed within the component to fetch details for the specific movie.

Ensuring Type Safety of our Angular 19 App

To ensure type safety and clarity in our Angular application, we'll define interfaces for the data structures we expect from our movie API. Interfaces help us define the shape of data objects and make our code more readable and maintainable. We'll create interfaces for movies, movie lists, credits, actors, images, and videos.

Create a src/app/models/movie.ts file and add the following interface for a movie:

export interface Movie {
  id: number;
  adult: boolean;
  backdrop_path: string;
  genre_ids: number[];
  original_language: string;
  original_title: string;
  overview: string;
  popularity: number;
  poster_path: string;
  release_date: string;
  title: string;
  video: boolean;
  vote_average: number;
  vote_count: number;
  revenue?: number;
  runtime?: string;
  status?: string;
  genres?: any[];
}

This interface outlines the structure of a movie object, including optional properties like revenue, runtime, status, and genres.

Next, add the movies interface:

export interface Movies {
  page: number;
  results: Movie[];
  total_pages: number;
  total_results: number;
}

The Movies interface includes pagination information and an array of Movie objects.

Next, create a src/app/models/credit.ts file and add interface for movie credits:

export interface Credits {
  cast: Actor[];
}

This interface represents the credits of a movie, containing an array of Actor objects.

Next, add an interface for movie actors:

export interface Actor {
  name: string;
  profile_path: string;
  character: string;
  id: number;
}

The Actor interface describes an actor's basic details, including their name, profile picture path, character they played, and ID.

Next, create a src/app/models/image.ts file and add the following interfaces:

export interface Images {
  backdrops: Image[];
}

export interface Image {
  file_path: string;
}

The Images interface includes an array of Image objects, and the Image interface represents an individual image with a file path. Next, create a src/app/models/video.ts file and add:

export interface Videos {
  results: Video[];
  id: string;
}

export interface Video {
  key: string;
  site: string;
}

The Videos interface includes an array of Video objects, and the Video interface describes a video's key and the site where it's hosted.

Adding a Movies API Angular 19 Service

To fetch movie data from an external API and manage API interactions efficiently, we'll create a service in Angular. This service will use HttpClient to make HTTP requests to a movie database API.

Step 1: Generate the Movies Service

First, head to a terminal and run the following command to generate a new service:

ng g s services/movies

This command creates a new service file (movies.service.ts) in the src/app/services directory.

Step 2: Generate Environment Variables

Next, generate the environment variables files using the Angular CLI:

ng g environments

This command creates environment configuration files in the src/environments directory.

Step 3: Add API Key to Environment Variables

Open the src/environments/environment.development.ts file and add your API key for accessing the movie database:

export const environment = {
    apiKEY: 'dadb019730c0075868955d1ec94040bb'
};

Make sure to replace dadb019730c0075868955d1ec94040bb with your own API key.

Step 4: Provide HttpClient in App Configuration

To use HttpClient in your Angular 19 application, you need to provide it in your application's configuration. Open the src/app/app.config.ts file and add the following code:

// [...]
import { provideHttpClient } from '@angular/common/http';

export const appConfig: ApplicationConfig = {
  providers: [..., provideHttpClient()]
};

Step 5: Implement the Movies Service

Now, let's implement the methods to fetch movie data in the MoviesService. Open the src/app/services/movies.service.ts file and start by adding the following imports:

import { Injectable, inject } from '@angular/core';
import { environment } from '../../environments/environment';
import { HttpClient } from '@angular/common/http';
import { Movie, Movies } from '../models/movie';
import { map } from 'rxjs';
import { Videos } from '../models/video';
import { Credits } from '../models/credit';
  • inject for injecting services.
  • environment: Imports environment variables where API key is stored.
  • HttpClient: Used to make HTTP requests to the API.
  • Movie, Movies, Videos, Credits: Interfaces defining the structure of the data returned by the API.

Defining Base URL for Movie Images

Next, define and export the base URL for fetching movie images from the API.

export const imagesBaseUrl = 'https://image.tmdb.org/t/p/';

Initializing Variables and Injecting HttpClient

Next, define the following variables and inject HttpClient:

export class MoviesService {
  private apiUrl = 'https://api.themoviedb.org/3';
  private apiKey = environment.apiKEY;
  private httpClient = inject(HttpClient);
  constructor() { }

This initializes private properties for API URL, API key, and an instance of HttpClient.

Getting Movies by Type

Next, define the fetchMoviesByType method:

  fetchMoviesByType(type: string, pageNumber = 1) {
    return this.httpClient
      .get<Movies>(`${this.apiUrl}/movie/${type}?page=${pageNumber}&api_key=${this.apiKey}`)
  }

This method will be used to fetch movies of a specific type (e.g., popular, top-rated) from the API. It accepts type (e.g., 'popular', 'top_rated') and pageNumber as parameters and constructs the API URL with the specified type and page number and makes an HTTP GET request using HttpClient.

Getting Similar Movies

Next, define the fetchSimilarMovies method:

  fetchSimilarMovies(id: string) {
    return this.httpClient
      .get<Movies>(
        `${this.apiUrl}/movie/${id}/similar?api_key=${this.apiKey}`
      )
      .pipe(map((data)=> data.results));
  }

This method will be used to fetch movies similar to a specified movie by its ID. It constructs the API URL for similar movies and makes an HTTP GET request. It uses pipe and map operators from RxJS to extract the results property from the API response.

Getting Movie by ID

Next, define the fetchMovieById method:

  fetchMovieById(id: string) {
    return this.httpClient.get<Movie>(
      `${this.apiUrl}/movie/${id}?api_key=${this.apiKey}`
    )
  }

This method will be used to fetch details of a specific movie by its ID. It constructs the API URL for the movie details and makes an HTTP GET request.

Getting Movie Videos

Next, define the fetchMovieVideos method:

  fetchMovieVideos(id: string) {
    return this.httpClient
      .get<Videos>(
        `${this.apiUrl}/movie/${id}/videos?api_key=${this.apiKey}`
      )
      .pipe(map((data) => data.results))
  }

This method will be used to fetch videos (trailers, teasers) associated with a specific movie by its ID. It constructs the API URL for movie videos and makes an HTTP GET request. It uses pipe and map operators to extract the results property from the API response.

Getting Movie Cast

Finally, define the fetchMovieCast method:

  fetchMovieCast(id: string) {
    return this.httpClient
      .get<Credits>(
        `${this.apiUrl}/movie/${id}/credits?api_key=${this.apiKey}`
      )
      .pipe(map((data) => data.cast))
  }

This method will be used to fetch the cast (actors) of a specific movie by its ID. It constructs the API URL for movie credits and makes an HTTP GET request. It uses pipe and map operators to extract the cast property from the API response.

This MoviesService provides methods to fetch various movie-related data from an external API. It encapsulates the logic for making HTTP requests and handling API responses, allowing other parts of the application to easily consume and utilize movie data.

Summary

We've successfully set up a Movies API service in Angular 19 by following these steps:

  1. Generated the Movies Service: Created a service using Angular CLI v19.
  2. Configured Environment Variables: Added the API key in the environment configuration file.
  3. Provided HttpClient: Configured HttpClient in the application's configuration.
  4. Implemented API Methods: Added methods in the MoviesService to fetch popular, top-rated, and now-playing movies, as well as movie details, credits, images, and videos.

With this setup, our Angular 19 application can now interact with the movie database API to fetch and display movie data.

Implementing the Movie Component

The MovieComponent is an Angular standalone component responsible for rendering the visual representation of a single movie. It receives movie data through its movie input property and utilizes Angular's template and styling capabilities to present the movie information to the user.

Open a terminal and run the following command:

ng g c components/movie

Open the src/app/components/movie/movie.component.ts file and add the following imports:

import { Input } from '@angular/core';
import { Movie } from '../../models/movie';
import { DatePipe } from '@angular/common';
import { imagesBaseUrl } from '../../services/movies.service';
import { RouterModule } from '@angular/router';

Next, add the date pipe, and router module to the imports array of the standalone component:

@Component({
  selector: 'app-movie',
  standalone: true,
  imports: [DatePipe, RouterModule],
  templateUrl: './movie.component.html',
  styleUrl: './movie.component.css'
})

Next, define a public property imagesBaseUrl and an input property named movie of type Movie:

export class MovieComponent {
  public imagesBaseUrl = imagesBaseUrl;
  @Input() movie!: Movie;
}

The @Input() decorator indicates that the property can receive data from its parent component. The ! symbol after movie is TypeScript's non-null assertion operator, which tells TypeScript that movie will be initialized by the parent component and won't be null or undefined.

For the component template, add the following HTML:

<a
  routerLink="/show-movie/{{ movie.id }}"
  class="w-full min-w-[230px] h-90 overflow-hidden block rounded relative hover:scale-105 transition-all">

  @if(movie.poster_path){
  <img
    class="w-full"
    [src]="imagesBaseUrl + '/w185/' + movie.poster_path"
    [alt]="movie.title"
  />
  }

  <div class="absolute bottom-0 h-30 bg-black/60 p-2 w-full text-white">
    <h2 class="text-ellipsis text-lg font-semibold">
      {{ movie.title }}
    </h2>

    <div class="flex justify-between bottom-0">
      <p>
        {{ movie.release_date | date }}
      </p>
      <p class="bg-black text-white rounded m-0 text-sm">
        Rating: {{ movie.vote_average }}
      </p>
    </div>
  </div>
</a>

This component allows users to click on a movie poster to view its details. It dynamically populates movie data and handles conditional rendering of the poster image. Overall, it provides a visually appealing and interactive way to browse and explore movies.

This is how it should look like:

angular 19 tutorial

Implementing the Movies Component with Infinite Scrolling

The movies page with infinite scrolling provides users with a convenient and engaging way to explore a large collection of movies, presenting essential details in an aesthetically pleasing card format while offering seamless navigation and responsive design.

The page dynamically loads additional movie cards as the user scrolls down, providing a seamless browsing experience without the need for pagination.

Go back to your terminal and run the following command:

npm install ngx-infinite-scroll --save

Next, open the src/app/pages/movies/movies.component.ts file and start by adding the following imports:

import { Component, DestroyRef, inject } from '@angular/core';
import { MoviesService } from '../../services/movies.service';
import { AsyncPipe } from '@angular/common';
import { Movie } from '../../models/movie';
import { MovieComponent } from '../../components/movie/movie.component';
import { InfiniteScrollModule } from "ngx-infinite-scroll";
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

The import statements in the Angular component file provide essential dependencies for building a functional component. They include the @Component decorator for marking components, the movies service for data fetching, the async pipe for handling asynchronous data, the Movie interface type safety, the movie component for visual representation, and a module for additional features like infinite scrolling. These imports collectively enable the component to interact with data, implement UI features, and manage resources effectively.

Next, add the async pipe, movie component and infinite scroll module to the imports array of the standalone component:

@Component({
  selector: 'app-movies',
  standalone: true,
  imports: [AsyncPipe, MovieComponent, InfiniteScrollModule],
  templateUrl: './movies.component.html',
  styleUrl: './movies.component.css'
})

Next, inject the movies and DestroyRef services and call the fetchMoviesByType method as follows:

private  moviesService  =  inject(MoviesService);
private  pageNumber  =  1;
private destroyRef  =  inject(DestroyRef)
public  moviesObs$  =  this.moviesService.fetchMoviesByType('popular', this.pageNumber);
public  moviesResults:  Movie[] = [];

These initialize properties within the component's class, including a service instance for fetching movies, a page number, and a resource for managing component destruction. It also defines an observable property for storing fetched movie data and an array for storing the results.

Next, in the ngOnInit() life-cycle method, subscribe to the movies observable and assign the results to the moviesResults array:

ngOnInit(){
  this.moviesObs$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => {
    this.moviesResults  =  data.results;
  });
}

In the ngOnInit lifecycle hook, we're subscribing to the moviesObs$ observable to get movie data and update the moviesResults property when data is received. We use the pipe operator to chain operators onto the observable. The takeUntilDestroyed operator is used here to automatically unsubscribe from the observable when the component is destroyed, preventing memory leaks.

Overall, this ensures that movie data is fetched when the component is initialized, and the moviesResults property is updated accordingly. The use of takeUntilDestroyed ensures that subscriptions are properly cleaned up when the component is destroyed, preventing memory leaks.

Next, define the onScroll() method which gets called when the user scrolls to the bottom:

onScroll():  void {
  this.pageNumber++;
  this.moviesObs$  =  this.moviesService.fetchMoviesByType('popular', this.pageNumber);
  this.moviesObs$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((data) => {
    this.moviesResults  =  this.moviesResults.concat(data.results);
  });
}

This function helps with the continuous loading of movie data as the user scrolls down the page, providing a seamless browsing experience. It ensures that new movie data is fetched and added to the existing movies array without losing previously fetched data.

It increments the pageNumber property, indicating that the next page of data should be fetched. Then, fetches movies for the next page using the fetchMoviesByType method of the moviesService. It subscribes to the returned observable to handle the emitted movie data. It also uses takeUntilDestroyed to ensure the subscription is cleaned up properly when the component is destroyed. Within the subscription callback, the new movie results are concatenated with the existing moviesResults array. This ensures that the new movie data is appended to the existing list, preserving previously fetched data.

In the component template movies.component.html, add the following HTML:

<div infiniteScroll (scrolled)="onScroll()" class="container mx-auto pt-20">
  <div class="grid grid-cols-[repeat(auto-fit,230px)] gap-5 justify-center">
    @for(movie of moviesResults; track movie.id){
      <app-movie [movie]="movie"></app-movie>
    }
  </div>
</div>

This code adds a movies container with an infinite scroll feature and a grid layout to display movie cards. The container div element uses the infiniteScroll directive to enable infinite scrolling functionality. The (scrolled) event is bound to the onScroll() method, which is triggered when the user scrolls. Using the @for syntax, it loops through each movie in the moviesResults array, tracking the id of each movie for efficient rendering and renders the movie component while binds the movie object to the movie input property of the app-movie component, passing the movie data for rendering.

With these changes, our movies page should now have infinite scrolling functionality, allowing users to scroll through a large collection of movies seamlessly. New movies will be fetched and appended to the existing list as the user scrolls down the page.

You can implement the other components in the same way. If you are stuck, take a look the code from this repository.

Conclusion

Throughout this Angular 19 tutorial, we've created a robust movies application leveraging Angular 19, Tailwind CSS, HttpClient, and an external REST API. Along the way, we've explored key Angular features such as standalone components, API integration, reactivity with Observables, infinite scrolling, and dynamic UI updates.

By implementing these features, you've gained hands-on experience in modern web development practices, improving both performance and user experience. With Angular 19's latest enhancements, you are now well-equipped to build scalable, maintainable, and highly interactive web applications in 2025 and beyond.

We encourage you to take this knowledge further by experimenting with additional Angular features, customizing UI elements with Tailwind CSS, and integrating more advanced API functionalities. Keep building, keep exploring, and stay ahead with Angular 19!


  • Date: