Unraveling Angular 2 Books, Chapter 1, Example 5

The page shows a list of dives, it has "add a new dive", "clean dives" and a search box that filters the displayed list when you enter it.

This is the template:

<div class="container-fluid"> <h1>My Latest Dives (Angular/TypeScript)</h1> <div class="row"> <div class="col-sm-5"> <button class="btn btn-primary btn-lg" [disabled]="!enableAdd()" (click)="addDive()"> Add new dive </button> <button class="btn btn-danger btn-lg" (click)="clearDives()"> Clear dives </button> </div> <div class="col-sm-4 col-sm-offset-3"> <input #searchBox class="form-control input-lg" placeholder="Search" (keyup)="0" /> </div> </div> <div class="row"> <div class="col-sm-4" *ngFor="let dive of dives | contentFilter:searchBox.value"> <h3>{{dive.site}}</h3> <h4>{{dive.location}}</h4> <h2>{{dive.depth}} feet | {{dive.time}} min</h2> </div> </div> </div> 

This is the component code:

 import {Component} from '@angular/core'; @Component({ selector: 'divelog', templateUrl: 'app/dive-log.template.html' }) export class DiveLogComponent { public dives = []; private _index = 0; private _stockDives = [ { site: 'Abu Gotta Ramada', location: 'Hurghada, Egypt', depth: 72, time: 54 }, { site: 'Ponte Mahoon', location: 'Maehbourg, Mauritius', depth: 54, time: 38 }, { site: 'Molnar Cave', location: 'Budapest, Hungary', depth: 98, time: 62 }]; public enableAdd() { return this._index < this._stockDives.length; } public addDive() { if (this.enableAdd()) { this.dives.push(this._stockDives[this._index++]); } } public clearDives() { this.dives = []; this._index = 0; } } 

This is the filter code:

 import {Pipe, PipeTransform} from '@angular/core'; @Pipe({name: 'contentFilter'}) export class ContentFilterPipe implements PipeTransform { transform(value: any[], searchFor: string) : any[] { if (!searchFor) return value; searchFor = searchFor.toLowerCase(); return value.filter(dive => dive.site.toLowerCase().indexOf(searchFor) >= 0 || dive.location.toLowerCase().indexOf(searchFor) >= 0 || dive.depth.toString().indexOf(searchFor) >= 0 || dive.time.toString().indexOf(searchFor) >= 0); } } 

The filter starts and the list gets rendered each time it is entered in the search field, but not when the "add" button is clicked. If I have something in the search box, the "add" button will not change the list of divers, even if the contents of the search box allows you to display new elements. How do I change the code so that clicking the "add" button causes a repeated display of the displayed list of dives?

+1
source share
1 answer

You have a clean channel , so

its transform method will only execute when it detects a clean change to an input value.

For your case

 *ngFor="let dive of dives | contentFilter:searchBox.value" 

input value will be dives and searchBox.value

According to angular2 pipe guide:

A pure change is either a change to a primitive input value (String, Number, Boolean, Symbol) or a reference to the changed object (Date, Array, Function, Object).

  • Adding a dive does not change the reference to the array (dives) - therefore, the transform method is not executed.
  • When something is entered into the filter input, searchBox.value changes - therefore, transform is executed.

So, one of the possible solutions is to always have a new reference array every time a div is added:

Just replace:

 this.dives.push(this._stockDives[this._index++]); 

with:

 this.dives = this.dives.concat(this._stockDives[this._index++]); 

or

 this.dives = [...this.dives, this._stockDives[this._index++]]; 

The second way to do this is to use an unclean channel :

 @Pipe({name: 'contentFilter', pure: false }) 
+3
source

Source: https://habr.com/ru/post/1261596/


All Articles