Link to home
Start Free TrialLog in
Avatar of Cynthia Hill
Cynthia HillFlag for United States of America

asked on

Angular 2 Pipe - Multipe Filters

Hello -

I'm working with pipes to filter a data set. I am new to Angular 2...so I am baby stepping my way into the full functionality I am trying to implement.

I'm working to add two separate filters...looking at two separate fields. I want to do them separately b/c the data set the filters will be applied to will be large....and response times for the second filter (which will be searching a name field) will be slower than response times for the 1st filter (which will be looking at an ID).

I've implemented the search functionality to look at two fields...which is great. However, I want it to not return anything unless something is entered into one of the search boxes. When i was working with just one filter for the ID field...i was able to do this using
if (!IDSearch) return null

Open in new window

. If  I did not have that specified...it caused problems when the user changed IDs. How do I add similar logic to when using the two search boxes?

Below is the code for my pipe component.


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

@Pipe({
  name: 'employeeSelection'
})
export class EmployeeSelectionPipe implements PipeTransform {


//CH Multiple Search Play
public transform(items: any[], IDSearch: string, nameSearch: string) {
    if (items && items.length){
            return items.filter(item =>{

                if (IDSearch && item.ID.toLowerCase().indexOf(IDSearch.toLowerCase()) === -1){
                    return false;
                }
                if (nameSearch && item.EmployeeName.toLowerCase().indexOf(nameSearch.toLowerCase()) === -1){
                    return false;
                }

                return true;
           })
        }
        else{
            return null;
        }
  
    }

  }

export const appPipes = [EmployeeSelectionPipe];

Open in new window

Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

I just need to understand are you passing your dataset through each filter

let a of items | filer1:Criteria1 | filter2:Criteria2

Open in new window

Are you looking for something like this?
public transform(items: any[], IDSearch: string, nameSearch: string) {
    if (items && items.length) {
        return items.filter(item => {
            if (IDSearch && item.ID) {
                if (nameSearch && item.EmployeeName) {
                    return (item.ID.toLowerCase().indexOf(IDSearch.toLowerCase()) === -1) || (item.EmployeeName.toLowerCase().indexOf(nameSearch.toLowerCase()) === -1);
                } else {
                    return (item.ID.toLowerCase().indexOf(IDSearch.toLowerCase()) === -1);
                }
            } else if (nameSearch && item.EmployeeName) {
                return (item.EmployeeName.toLowerCase().indexOf(nameSearch.toLowerCase()) === -1);
            }
            return true;
        })
    } else {
        return null;
    }
}

Open in new window


-saige-
Avatar of Cynthia Hill

ASKER

Hey Julian - Yes...

I am passing the dataset through each filter in my HTML file.

  <ng-container *ngFor="let user of users | employeeSelection:attuidSearch: nameSearch">

Open in new window


Here is a slimmed down version of the HTML file. I have more fields in the official version...but this gives you an idea. You will also notice I am splitting different types of fields into separate tables (to give the output a more organized look on the screen and so its easier on make sense of the data since I will have a good number of fields to display).
<div >
  <!-- style="text-align:center" -->
  <h1>
    Employee Profile
    </h1>
</div>
<div>
  <!-- Search Text -->
  <div>
<h4>Enter ID</h4>  <input [(ngModel)]="IDSearch" />
<h4>Enter Employee Name</h4>  <input [(ngModel)]="nameSearch" />
    <hr>
   </div>
<!-- <hr> -->
  <h4>PERSONAL INFORMATION</h4>
  <table class="table">
      <!-- <caption><h3>PERSONAL INFORMATION</h3></caption> -->
  <ng-container *ngFor="let user of users | employeeSelection:IDSearch: nameSearch">
      <tr>
        <th>ID</th><td>{{user.ID}}</td>
        <th>Employee Name</th><td>{{user.EmployeeName}}</td>
      </tr>
    
      <tr>
        <th>Work Phone</th><td>{{user.Phone}}</td>
        <th>Cell Phone</th><td>{{user.CellPhone}}</td>
      </tr>
      <tr>
        <th>Email Address</th><td>{{user.eMailAddress}}</td>
        <th>Employee Status</th><td>{{user.EmployeeStatus}}</td>
      </tr>
            </ng-container>
</table>


  <h4>JOB INFORMATION</h4>
  <table class="table">
    <ng-container *ngFor="let user of users | employeeSelection:IDSearch: nameSearch">
        <tr>
          <th>Job Key</th><td>{{user.JobKey}}</td>
          <th>Job Description</th><td>{{user.JobDescription}}</td>
        </tr>
      
      </ng-container>
</table>
</div>

Open in new window

Hey IT Saige - Thanks for your response. That does not seem to be doing what I need.

I do not want any records from the dataset to load until something is entered into one of the search filters. When I apply the code you suggested...when I refresh the screen (or remove values from the filters) all records return by default.  

I do not want any records until something is entered.

When I was working with just one filter...
if (!IDSearch) return null

Open in new window

...did the trick...but not sure how to do something similar while having it look at both fields.
This works for me
Comonent
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'EE Angular Sample 5 (Angular 4.3)';
  users = [
    {
        "firstName": "Clark",
        "lastName": "Kent",
        "job": "Reporter",
        "id": 20
    },
    {
        "firstName": "Bruce",
        "lastName": "Wayne",
        "job": "Business Owner",
        "id": 30
    },
    {
        "firstName": "Peter",
        "lastName": "Parker",
        "job": "Photographer",
        "id": 40
    },
    {
        "firstName": "Tony",
        "lastName": "Stark",
        "job": "Business Owner",
        "id": 25
    }
]
}

Open in new window

Template
Id <input [(ngModel)]="id" />
Lastname <input [(ngModel)]="lastName" />

<table class="table">
<ng-container *ngFor="let user of users | search:id:lastName">
      <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>

Open in new window

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

@Pipe({
  name: 'search'
})
export class SearchPipe implements PipeTransform {
  public transform(items: any[], id: string, lastName:string) {
    return items.filter(item => {
      if (id && item.id.toString().indexOf(id) > -1) return true;
      if (lastName && item.lastName.toLowerCase().indexOf(lastName.toLowerCase()) > -1) return true;
    });
  }
}

export const appPipes = [SearchPipe];

Open in new window


Working sample here
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hey Julian - that does what I want for now. I have at least 2 other items for the functionality I want to work in...but because I am learning...I need to take things in chunks so I have a better chance of following the solutions.

Thanks!
You are welcome.