Tuesday, 28 March 2017

Simple and advanced search using pipe in Angular

Angular 4Angular 5Angular 2+SearchPipes

In this article I will be explaining about how to implement a simple and advanced search using pipe concept. I have explained in my previous article about how to do a simple search or filtering using angular js 1 as well. If you want to compare both implementation you can refer this link.

1. Simple search using pipe in Angular
2. Example of search using different array structure
3. Advanced search using pipe in Angular
4. Search entire Array

1. Simple search using pipe in Angular


OK, let’s start with our Angular 2 simple search implementation using pipe.

I will share the app module code as well to avoid any confusion

App module code



import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import {FilterPipe} from './pipes'

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent,FilterPipe
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


FilterPipe is nothing but our pipe name and './pipe' is the typscript file path which has pipe code.

Let us check our component code

App component



import { Component } from '@angular/core';
import {FilterPipe} from './pipes'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title:String;
  names:any;
  constructor(){
    this.title = "Angular 2 simple search";
        this.names = ['Prashobh','Abraham','Anil','Sam','Natasha','Marry','Zian','karan']
  }
}


Here you can see a simple array which contains some names. The template url is nothing but our html.

Template [ templateUrl: './app.component.html']



<div>
  <h3> {{title}}</h3>
  <input type="text" [(ngModel)]="queryString" id="search" placeholder="Search to type">

  <ul>
    <li *ngFor="let n of names | FilterPipe: queryString">
      {{n}}
    </li>
  </ul>
</div>


Now create a pipe and name as FilterPipe. Check below code for pipe.

Pipe


import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'FilterPipe',
})
export class FilterPipe implements PipeTransform {
    transform(value: any, input: string) {
        if (input) {
            input = input.toLowerCase();
            return value.filter(function (el: any) {
                return el.toLowerCase().indexOf(input) > -1;
            })
        }
        return value;
    }
}


We are done. Run the application and start typing on text box you can see filtered result.

You can go to our GitHub page and download all the code as well. Download code from GitHub page.

2. Example of search using different array structure


Now let us check with another example, above example is searching through a simple list. We will modify our array and see how it will work.

Modified Array


this.list = [
  {name:'prashobh',age:'25'},
  {name:'Abraham',age:'35'},
  {name:'Sam',age:'45'},
  {name:'Anil',age:'15'},
  {name:'Mariya',age:'24'},
  {name:'Crock',age:'28'},
  {name:'Ram',age:'21'},
]

Modified pipe


import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'FilterPipe',
})
export class FilterPipe implements PipeTransform {
    transform(value: any, input: string) {
        if (input) {
            input = input.toLowerCase();
            return value.filter(function (el: any) {
                return el.name.toLowerCase().indexOf(input) > -1;
            })
        }
        return value;
    }
}

I just updated to "el.name", it will search through the array and find the respective names. Ok now let us check with another example which can search through both age and name.


import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'FilterPipe',
})
export class FilterPipe implements PipeTransform {
    transform(value: any, input: string) {
        if (input) {
            input = input.toLowerCase();
            return value.filter(function (el: any) {
                return el.name.toLowerCase().indexOf(input) > -1 ||
                    el.age.toLowerCase().indexOf(input) > -1;
            })
        }
        return value;
    }
}

You can easily update this pipe for your needs.

3. Advanced search using pipe in Angular


We have already seen how the simple search works in angular, now let us check little more advanced search. You can provide a list of parameters to pipe which you want to search. Let us check with one example.

Component code


export class AppComponent {
  title:String;
  names:any;
  constructor(){
    this.title = "Angular advanced search";
    this.list = [
   {name:'prashobh',age:'25'},
   {name:'Abraham',age:'35'},
   {name:'Sam',age:'45'},
   {name:'Anil',age:'15'},
   {name:'Mariya',age:'24'},
   {name:'Crock',age:'28'},
   {name:'Ram',age:'21'},
   ]
   this.searchableList = ['name','age']  
  }
}

There is no change except I have added a list "searchableList". This list we will be passing to our custom pipe, check below updated html for that.


<input type="text" [(ngModel)]="queryString" id="search" placeholder="Search to type">
  <ul>
    <li *ngFor="let n of list | FilterPipe: queryString : searchableList ">
      {{n.name}} ({{n.age}})
    </li>
  </ul>

We can pass array/object/string to a customer pipe, I am not explaining those in details here. Now let us check our updated pipe.

Updated pipe


import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'FilterPipe',
})
export class FilterPipe implements PipeTransform {
    transform(value: any, input: string, searchableList: any) {
        if (input) {
            input = input.toLowerCase();
            return value.filter(function (el: any) {
                var isTrue = false;
                for (var k in searchableList) {
                    if (el[searchableList[k]].toLowerCase().indexOf(input) > -1) {
                        isTrue = true;
                    }
                    if (isTrue) {
                        return el
                    }
                }
            })
        }
        return value;
    }
}

We are done, you can simply add any parameters which you want to be searchable. You can use above plunker for your testing.

4. Search entire Array


If you want your pipe to be searched for entire array, you can use below pipe.


@Pipe({
    name: 'FilterPipe'
})

export class FilterPipe implements PipeTransform {
    transform(value: any, args?: any): any {

        if (!value) return null;
        if (!args) return value;

        args = args.toLowerCase();

        return value.filter(function (item: any) {
            return JSON.stringify(item).toLowerCase().includes(args);
        });
    }
}

In this article we have discussed about doing a simple and advanced search in angular 2+ using pipe concept with different examples.

Angular 4Angular 5Angular 2+SearchPipes

Related Info

1. Share data between components using a service file.

2. Create reusable component and share data between them.

3. Angular client side pagination.

4. Angular show more/less pagination

21 comments :

  1. what's queryString?

    ReplyDelete
    Replies
    1. It is model name, any name you can add.

      Delete
  2. I'm getting this error when try to implement search filter.

    ERROR
    TypeError: el.toLowerCase is not a function
    Stack trace:
    FilterPipe.prototype.transform/<@webpack-internal:///../../../../../src/app/pipes/filter.pipe.ts:18:28

    Please suggest me how to fix this issue.

    ReplyDelete
    Replies
    1. Try to put a debugger in el.toLoweCase(), may be you need to write el.somename(which you want to filter) ...or right if(el && el.toLowerCase())

      Delete
  3. Can't bind to 'ngModel' since it isn't a known property of 'input'.
    [ERROR ->][(ngModel)]="queryString" id="search">

    ReplyDelete
    Replies
    1. Did you imported FormsModule to your module ?
      import { FormsModule } from '@angular/forms';
      Check above module code for more info

      Delete
  4. thanks for this useful information...

    ReplyDelete
  5. thanks a lot, no one explained it better, once more thanks a lot!

    ReplyDelete
  6. I have this problem, because this isProjectSelected is an array with objects.
    Could you help me
    Uncaught Error: Template parse errors:
    The pipe 'FilterPipe' could not be found placeholder="Search to type"
    table id="myTable" fxLayout="column"
    td *ngFor ="[ERROR ->]let n of isProjectSelected() | FilterPipe: queryString " {{n.name}} td
    table
    d": ng:///AppModule/BudgetPlanningComponent.html@29:23

    ReplyDelete
    Replies
    1. Please put your codes in the plunker and share here, so that we can look into that.

      Delete
    2. Thank you I fixed it, but how it is possible when the item is founded to be selected.

      Delete
    3. Great to hear that. For selecting you can just assign the selected value to your model. Something similar I have done for autocomplete : -http://www.angulartutorial.net/2018/03/create-angular-autocomplete-angular-25.html

      Delete
  7. I have created 2 icons into the search 1. search and 2. times how is possible when click x to reset the input search.

    ReplyDelete
    Replies
    1. I guess you are asking for a way to clear the search box, you can try below code

      input type="text" [(ngModel)]="queryString" id="search" placeholder="Search to type">

      img scr="/icon" *ngIf="queryString.length>0" (click)="queryString = '' " alt="clear">

      Delete
    2. Thank you, I made in another way and your code works too, how it is possible somehow when we type a name if is found to make like a click with enter that the last name is found or if is one name found in the array that name to be selected. i don't wan't to show in my search but just to be active.

      Delete
  8. what if I want to search min and max date?

    from this date to this date
    I want that kind of filter ?
    is it possible ?

    ReplyDelete
    Replies
    1. Yes it is possible. You can modify the pipe to read date, may be pass a flag. I don't have have a ready made code in my hand now.

      Delete