Hello - I've tried a handful of different code samples, but can not figure out how to add a search box to an Angular 2 table.
Here is my app.component.html code
<!--The content below is only a placeholder and can be replaced.--><div style="text-align:center"> <h1> Welcome to {{title}}! </h1> <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="></div><div> <input [(ngModel)]="query"> <div *ngFor="let user of users | search:'id':query">{{user.id}}</div><table class="table"><ng-container *ngFor="let user of users"> <tr> <th>First Name</th><td>{{user.firstName}}</td> <th>Last Name</th><td>{{user.lastName}}</td> </tr> <tr> <th>Job</th><td>{{user.job}}</td> <th>ID</th><td>{{user.id}}</td> </tr> </ng-container></table></div>
Where am I going wring. Should the code for the pipe be in a separate file? It did not seem to fix things when I tried...but that's probably because the code is not right.
Any assistance would be greatly appreciated! Thanks!
Web DevelopmentHTMLJavaScript
Last Comment
Julian Hansen
8/22/2022 - Mon
Julian Hansen
A few things going on here
1. Should Pipe be in a separate file
Answer: it does not have to but convention says to separate functionality into different files - whether that is a file per Pipe declaration or one file that exports all Pipes is a design decision you make.
2. Why is it not working. Let's look at how a pipe works. The transform takes at least 2 parameters. A list of items to filter and 1 or more filter args. In this case we are going to use 1.
How do we set it up.
First the view - we need an input to take the search and we need a model for the value. If we are going to be using ngModel then we need to add the Forms module to our app module and include it in the imports section
app.module.ts
This created (and added to my project) the file app.pipes.ts
I then defined my pipe as follows
import { Pipe, PipeTransform } from '@angular/core';@Pipe({ name: 'search'})export class SearchPipe implements PipeTransform { public transform(items: any[], filter: string) { // IF SEARCH TEXT IS EMPTY RETURN THE COMPLETE LIST if (!filter) return items; // OTHERWISE FILTER RESULTS BASED ON WHETHER filter IS IN firstName // lastName OR Job return items.filter(item => item.firstName.indexOf(filter) !== - 1 || item.lastName.indexOf(filter) !== -1 || item.job.indexOf(filter) !== -1) }}export const appPipes = [SearchPipe];
(refer note at the end)
Note the exported appPipes at the end - this is so I can declare any other pipes in this component add them to the exported appPipes array and in my module.ts I only need to import the appPipes array - like so
import { BrowserModule } from '@angular/platform-browser';import { NgModule } from '@angular/core';import { FormsModule } from '@angular/forms';import { AppComponent } from './app.component';// IMPORT THE exported appPipesimport { appPipes } from './pipes.pipe';@NgModule({ declarations: [ AppComponent, appPipes // INCLUDE IN OUR DECLARATIONS ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent]})export class AppModule { }
EDIT - Note Added
Note: when searching an object for text - we can check the relevant fields as we have done in this sample or if we want to search the whole object we can simply stringify the item and do an indexOf on the string
import { Pipe, PipeTransform } from '@angular/core';@Pipe({ name: 'search'})export class SearchPipe implements PipeTransform { public transform(items: any[], filter: string) { // IF SEARCH TEXT IS EMPTY RETURN THE COMPLETE LIST if (!filter) return items; // RETURN ANY ITEM THAT HAS THE filter STRING ANYWHERE IN THE OBJECT return items.filter(item => JSON.stringify(item).indexOf(filter) !== -1); }}export const appPipes = [SearchPipe];
because the pipe files were added in my main app folder. What is best practice? Should the app.pipe.ts file have been created in a separate "pipe" file?
Also, I notice the text box search is case sensitive. How do I make it work when a user enters in either upper or lower case text?
The intent for this table is to always only show one record (based on the ID a user enters...that is the only field I need it to filter off of). I can go back an repoint the search functionality to look at only the ID field later tonight when I have more time to play with it.
However, what I am not sure on is how to not have any records returned until the user enters in a search value.
In any event...I will play more with it tonight. Greatly appreciate your help so far!
1. Should Pipe be in a separate file
Answer: it does not have to but convention says to separate functionality into different files - whether that is a file per Pipe declaration or one file that exports all Pipes is a design decision you make.
2. Why is it not working. Let's look at how a pipe works. The transform takes at least 2 parameters. A list of items to filter and 1 or more filter args. In this case we are going to use 1.
How do we set it up.
First the view - we need an input to take the search and we need a model for the value. If we are going to be using ngModel then we need to add the Forms module to our app module and include it in the imports section
app.module.ts
Open in new window
Next we add the input to our component HTML view
Open in new window
This can go anywhere on your page - put it where it makes most sense.Also in the view we have to filter our results based on this value
Open in new window
We are going to pipe our results to the (to be defined) search Pipe and pass it the searchText to filter on.
Finally we need to define our pipe
Let's do it the right way.
I created my pipes file like so
Open in new window
This created (and added to my project) the file app.pipes.tsI then defined my pipe as follows
Open in new window
(refer note at the end)Note the exported appPipes at the end - this is so I can declare any other pipes in this component add them to the exported appPipes array and in my module.ts I only need to import the appPipes array - like so
Open in new window
And we are good to go.Working sample here
EDIT - Note Added
Note: when searching an object for text - we can check the relevant fields as we have done in this sample or if we want to search the whole object we can simply stringify the item and do an indexOf on the string
Open in new window
Full source using above methodOpen in new window