Filtering the Movies (Angular)

In this post we will create a pipe with Angular and bind it to an input field to filter a list of items. This will allow users to see the contents of the list change dynamically as they type their search terms.

The Zombie Movie Club app from my last few posts features a list of information about films featuring or related to the zombie genre, but had no search. Let’s use an Angular pipe to create filters.

A pipe will allow a list to be filtered based on a certain criteria. In the *ngFor block that itemizes the movies, we can apply our own custom filter using the | symbol. First, we need to generate the pipe.

ng generate pipe movie-filter

To create a filter, we need to implement the transform function. This is going to take some pipeData, which is going to be the list of films, and something to filter it by. In this first iteration, let’s simply filter using the title or genre fields by whatever is passed in. For each item that goes through the filter, movie below, check if it’s genre property includes the text from the filter.

transform(pipeData, pipeFilter): unknown {
  return pipeData.filter( movie => {
    return (
      movie['Genre'].toLowerCase().includes(filter) ||
      movie['Title'].toLowerCase().includes(filter) ||
      filter == ''
    );
  });
}

Note that I’ve converted both the search term and the title and genre fields to lowercase to make things more convenient for the user.

Using this is easy; just add it to the *ngFor block in the template. Angular has already hooked everything up so that it can be used throughout the app. This code will mean that only movies with the “Comedy” genre appear in the list.

<div class="card" *ngFor="let film of (movies | genreFilter: 'Comedy')"/>

Binding to a Form

What is required is a text box that the user can type into. As they type the data list of movies should be filtered to show only matching movies based on title or genre.

We need to bind the data in the text field to what is passed into the filter. We will use the ngModel which can be imported from the FormsModule provided by Angular.

First add the import statement to the app.module.ts:

import { FormsModule } from '@angular/forms';

Then include it in app’s import section:

imports: [
  BrowserModule,
  FormsModule
],

Next we can add a small form to the top of movie-list-component.html to display the text field. Note that the name attribute is necessary here; the ngModel binding requires it. This bit of code will bind whatever text is placed in the field to the filterText variable.

  <div class="container">
    <form>
      <div class="form-group">
        <label for="filterText">Filter on title or genre:</label>
        <input
          class="form-control mt-2"
          type="text"
          [(ngModel)]="filterText"
          name="filterText"
          id="filterText"
        />
      </div>
    </form>
    <p></p>
  </div>

This variable can now be used to filter the list of movies

<div 
     class="card" 
     style="width: 18rem;"
     *ngFor="let film of (movies | genreFilter: filterText); let i=index">

The filtering works quickly and smoothly. All the work is being done on the client device so no additional calls to the host are required. Here is a screen shot that brings back the two Zombieland movies.