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.