Wednesday, February 26, 2020

Angular 8/9 | Custom Filter Pipe Get Child Values Based On Parent Id Passed

In Angular applications, we can do so by using Filter Pipes which can be easily used on a data object with custom login.
Custom Filter Pipe

The Pipe Filter we are going to discuss will take a custom [key] name on which we want to filter child values. For example, there are following two data sets:
recipes = [
    {
       "id":1,
       "name":"Burger"
    },
    {
       "id":2,
       "name":"French Fries"
    },
    {
       "id":3,
       "name":"Chowmein"
    }
   ]


  ingredients = [
    {
       "id":1,
       "parentId":1,
       "name":"Potatoes"
    },
    {
       "id":2,
       "parentId":1,
       "name":"Beans"
    },
    {
       "id":3,
       "parentId":1,
       "name":"Buns"
    },
    {
       "id":4,
       "parentId":1,
       "name":"Carrots"
    },
    {
       "id":5,
       "parentId":2,
       "name":"Cooking Oil"
    },
    {
       "id":6,
       "parentId":2,
       "name":"Potatoes"
    },
    {
       "id":7,
       "parentId":2,
       "name":"Pepper"
    },
    {
       "id":8,
       "parentId":2,
       "name":"Salt"
    },
    {
       "id":9,
       "parentId":3,
       "name":"Hakka Noodles"
    },
    {
       "id":10,
       "parentId":3,
       "name":"Green Vegies"
    },
    {
       "id":11,
       "parentId":3,
       "name":"Tomato Sauce"
    },
    {
       "id":12,
       "parentId":3,
       "name":"Soya Souce"
    }
   ]
Create A Filter Pipe
Using NG CLI tool, we can create a new Filter pipe using the generate command s shown below:
$ ng generate pipe pipes/filterParent
Above command will create a new pipe file pipes/filter-parent.pipe.ts with the following code in it:
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filterParent'
})
export class FilterParentPipe implements PipeTransform {

  transform(value: any, ...args: any[]): any {
    return null;
  }

}
As we have created it using NG CLI’s generate command, so it will do it automatically:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { FilterParentComponentComponent } from './components/filter-parent-component/filter-parent-component.component';
import { FilterParentPipe } from './pipes/filter-parent.pipe';

@NgModule({
  declarations: [
    AppComponent,
    FilterParentComponentComponent,
    FilterParentPipe
  ],
  imports: [
    FormsModule, // <-- required to use [(ngModule)] in HTML component
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
FilterParent Pipe Upgrade
import { Pipe, PipeTransform } from '@angular/core';
import * as _ from 'lodash';

@Pipe({
  name: 'filterParent'
})
export class FilterParentPipe implements PipeTransform {

    transform(value: string, keyName: string, parentId: any, ): string {
        return _.filter(value, function (o) {
            return o[keyName] === +parentId;
        });
    }

}
Usage Of Filter In Template
Usage of this pipe is very simple, just add it using a pipe operator as shown below with a property name and second argument as the id of recipe selected in the select box
<h5>Select Recipe</h5>
<select name="recipes" [(ngModel)]="recipeModel">
    <option [value]="r.id" *ngFor="let r of recipes">{{r.name}}</option>
</select>

<h5>Ingredients</h5>
<ul>
    <li *ngFor="let ing of ingredients | filterParent:'parentId':recipeModel">
        {{ing.name}}
     </li>
</ul>