How to fix a ExpressionChangedAfterItHasBeenCheckedError - html

I have an application with a mat-autocomplete element in it with cities as options. The cities come from a database. There is a button to add an input element. This is done by having a div element with a *ngFor property that loops over a property in the component.ts file. When the add-button is clicked an element is added to the property and so an input is added. But when i type in a city name in the first input and then try to add an input element i get the ExpressionChangedAfterItHasBeenCheckedError.
I have found that a lot of people get this error but i've tried all the given solutions but non of them of them seem to work. Like :
startWith(''),
delay(0),
map(value => this._filter(value))
);
ngAfterViewInit(){
this.cd.detectChanges();
}
var request = new CityCreationRequestModel();
request.name = "";
Promise.resolve(null).then(() => this.reportGroupCreationRequest.cityReportGroups.push(request));
and trying with timeOuts.
this is my html file :
<div class="container">
<mat-card>
<mat-card-header>
<mat-card-title>Voeg een reportgroep toe</mat-card-title>
<mat-card-subtitle>Geef emailadressen op die verbonden worden met de rapporten van bepaalde steden</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<form (ngSubmit)="onSubmit()" #addReportGroup="ngForm" *ngIf="!isLoading">
<div *ngFor="let city of reportGroupCreationRequest.cityReportGroups" class="form-row">
<mat-form-field>
<input placeholder="Stad" required [(ngModel)]="city.name" type="text" matInput [formControl]="myControl" [matAutocomplete]="auto" name="cityInput">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let cityName of filteredOptions | async" [value]="cityName">
{{ cityName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>
<button mat-raised-button (click)="addCity()">Voeg een stad toe</button>
<div class="form-row">
<button mat-raised-button type="submit" [disabled]="!addReportGroup.valid" class="submitButton">Opslagen</button>
</div>
</form>
<mat-spinner [style.display]="isLoading ? 'block' : 'none'"></mat-spinner>
</mat-card-content>
</mat-card>
and this is my .ts file :
the filter if for the mat-autocomplete element
export class AddReportGroupComponent implements OnInit {
myControl = new FormControl();
filteredOptions: Observable<string[]>;
public reportGroupCreationRequest: ReportGroupCreationRequestModel = new ReportGroupCreationRequestModel();
public cities: Array<CityResponseModel>;
public cityNames: Array<string>;
private isLoading: boolean;
constructor(private reportGroupService: ReportGroupService,
private cd: ChangeDetectorRef) {
}
ngOnInit() {
this.isLoading = true;
this.reportGroupService.getCities().subscribe(result => {
this.cities = result;
this.cities.sort((a,b) => a.name.localeCompare(b.name));
this.cityNames = this.cities.map(c=>c.name);
}).add(()=> {
this.isLoading = false;
this.filteredOptions = this.myControl.valueChanges.pipe(
startWith(''),
delay(0),
map(value => this._filter(value))
);
});
this.reportGroupCreationRequest.cityReportGroups.push(new CityCreationRequestModel());
this.reportGroupCreationRequest.emailReportGroups.push(new EmailCreationRequestModel());
}
//doesn't seem to do anything
ngAfterViewInit(){
this.cd.detectChanges();
}
private _filter(value: string): string[] {
const filterValue = value.toLowerCase();
return this.cityNames.filter(cn => cn.toLowerCase().indexOf(filterValue) === 0);
}
addCity(){
var request = new CityCreationRequestModel();
request.name = "";
Promise.resolve(null).then(() => this.reportGroupCreationRequest.cityReportGroups.push(request));
}
and these are my models that I use :
export class ReportGroupCreationRequestModel {
public cityReportGroups: Array<CityCreationRequestModel> = new Array<CityCreationRequestModel>();
public emailReportGroups: Array<EmailCreationRequestModel> = new Array<EmailCreationRequestModel>();
}
export class CityCreationRequestModel {
public name: string;
}
Thanks in advance
I found a solution for the problem I had :
I used both [(ngModel)] and [FormsControl] and apparantly the [(ngModel)] was part of the problem so I only used [FormsControl] and the error is gone.
addCity(){
this.reportGroupCreationRequest.cityReportGroups[this.reportGroupCreationRequest.cityReportGroups.length - 1].name = this.myControl.value;
Promise.resolve(null).then(() => this.reportGroupCreationRequest.cityReportGroups.push(new CityCreationRequestModel()));
}
<div *ngFor="let city of reportGroupCreationRequest.cityReportGroups" class="form-row">
<mat-form-field>
<input placeholder="Stad" required type="text" matInput [formControl]="myControl" [matAutocomplete]="auto" name="cityInput">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let cityName of filteredOptions | async" [value]="cityName">
{{ cityName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</div>

Related

Angular material-autocomplete for searches with multiple words?

In my Angular project, I'm using material-autocomplete to search through some of my items. So far, it works as expected.
HTML
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{option}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
TS
myControl = new FormControl();
options: string[] = ['One', 'Two', 'Three'];
filteredOptions: Observable<string[]>;
ngOnInit() {
this.filteredOptions = this.myControl.valueChanges.pipe(
startWith(''),
map(value => this._filter(value))
);
}
private _filter(value: string): string[] {
const filterValue = value.toLowerCase();
if(filterValue == ''){
return []
}
return this.options.filter(option => option.toLowerCase().indexOf(filterValue) === 0);
}
This function works, but only for the first word in the search. For example, if you want to search for "Banana Apple", that will autocomplete if you type "B", but it won't autocomplete if you type "Apple." Is there a way to apply this search so that you can search for either word in a multi-word item?
You should change the last line of your _filter method:
return this.options.filter(option => option.toLowerCase().includes(filterValue));
This allows to you to filter finding in all of the value of your option.

Angular filter and binding (ngModelChange)

I'm working on the hotel project. I have a reservation screen. Here I ask the hotel name, region name, check-in and check-out dates, the number of adults and children. When the necessary information is entered, when I press the search button, I filter according to the values ​​there. I connected the date filter with html using the (NgModelChange) method, but I couldn't connect the html with the hotel and region methods correctly. I made a filter as an experiment, but I got the wrong result. I don't know where I'm making a mistake. How can I fix this?
.html
<form [formGroup]="form">
<mat-form-field>
<label>Which Hotel?</label>
<input type="text" matInput [matAutocomplete]="name" formControlName="name" (change)="changeHotel()" />
<mat-autocomplete #name="matAutocomplete">
<mat-option *ngFor="let hotel of filteredHotels | async" [value]="hotel">
{{hotel}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field>
<label>Which Region?</label>
<input type="text" matInput [matAutocomplete]="region" formControlName="region" (change)="changeRegion()" />
<mat-autocomplete #region="matAutocomplete">
<mat-option *ngFor="let region of filteredRegions | async" [value]="region">
{{region}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field>
<label>Entry Date?</label>
<input matInput [matDatepicker]="mdpStartDate" formControlName="startDate" (ngModelChange)="changeDate()">
<mat-datepicker-toggle matSuffix [for]="mdpStartDate"></mat-datepicker-toggle>
<mat-datepicker #mdpStartDate></mat-datepicker>
</mat-form-field>
<mat-form-field>
<label>Pay Date?</label>
<input matInput [matDatepicker]="mdpEndDate" formControlName="endDate" (ngModelChange)="changeDate()">
<mat-datepicker-toggle matSuffix [for]="mdpEndDate"></mat-datepicker-toggle>
<mat-datepicker #mdpEndDate></mat-datepicker>
</mat-form-field>
<br />
<mat-form-field>
<label>Adult Number?</label>
<input type="number" min="1" matInput formControlName="adult" (ngModelChange)="filterAge()">
</mat-form-field>
<mat-form-field>
<label>Chd Number?</label>
<input type="number" min="0" max="3" value="0" matInput formControlName="chd" (ngModelChange)="filterAge()">
</mat-form-field>
<button type="button" class="btn btn-success" (click)="search()">Search</button>
.ts
form = new FormGroup({
name: new FormControl(''),
region: new FormControl(''),
adult: new FormControl(1),
chd: new FormControl(0),
startDate: new FormControl(),
endDate: new FormControl(),
});
filtered: any[];
showList = false;
name = '';
regions: string[];
hotels: Hotel[] = [];
filteredHotels: Observable<string[]>;
filteredRegions: Observable<string[]>;
ngOnInit() {
this.regions = this.hotels.reduce((arr: string[], current) => {
if (!arr.includes(current.regionName)) {
arr.push(current.regionName);
}
return arr;
}, []);
this.filteredHotels = this.form.get("name").valueChanges
.pipe(
startWith(''),
map(v => {
return this.filterHotels(v)
})
);
this.filteredRegions = this.form.get("region").valueChanges
.pipe(
startWith(''),
map(value => this.filterRegions(value).map(h => h.regionName))
);
this.form.get("adult").valueChanges.
subscribe(v => {
this.adult = new Array(v).map(e => new Object)
});
this.form.get("chd").valueChanges
.subscribe(v => {
this.children = new Array(v).map(e => new Object)
});
this.hotelservice.getHotels().subscribe(
data => {
this.hotels = data;
this.dsHotels.data = data;
this.dsHotels.paginator = this.paginator;
},
err => {
console.error("Hata oluştu: ", err);
}
);
}
private filterHotels(value: string): string[] {
const name = value.toLowerCase();
return this.hotels
.map(x => x.hotelName)
.filter(option => option.toLowerCase().includes(name));
}
private filterRegions(value: string): Hotel[] {
const region = value.toLowerCase();
return this.hotels
.filter(hotel => hotel.regionName.toLowerCase().includes(region));
}
private isEqual(date1: Date, date2: Date) {
return date1.getDate() == date2.getDate() && date1.getMonth() == date2.getMonth() && date1.getFullYear() == date2.getFullYear();
}
private isDataEqualToDate(value1: any, date2: Date) {
if (value1 == null) return true;
return this.isEqual(new Date(value1), date2);
}
private getFilteredDate(): Hotel[] {
return this.hotels.filter(
x => this.isDataEqualToDate(this.form.get("startDate").value, new Date(x.checkInDate))
&& this.isDataEqualToDate(this.form.get("endDate").value, new Date(x.payDate))
);
}
changeHotel() {
this.dsHotels.data = this.filterHotels("value");
}
changeRegion() {
this.dsHotels.data = this.filterRegions("value");
}
changeDate() {
this.dsHotels.data = this.getFilteredDate();
}
filterAge() {
//this.dsHotels.data = this.hotels.filter(x => x.numberOfAd == this.form.get("adult").value && x.numberOfChd == this.form.get("chd").value);
this.dsHotels.data = this.hotels.filter(x => x.numberOfAd == x.numberOfChd);
}
search() {
this.showList = true;
this.filterHotels("");
this.filterRegions("");
this.changeDate();
}
As you created your form with reactive forms you can switch from event binding in template
< ... (change)="changeHotel()"
< ... (ngModelChange)="changeDate()">
to do it inside class.
ngOnInit() {
// ... initial logic
this.form.get('name').valueChanges.subscribe(this.changeHotel.bind(this))
this.form.get('region').valueChanges.subscribe(this.changeRegion.bind(this))
this.form.get('startDate').valueChanges.subscribe(this.changeDate.bind(this))
this.form.get('endDate').valueChanges.subscribe(this.changeDate.bind(this))
this.form.get('adult').valueChanges.subscribe(this.filterAge.bind(this))
this.form.get('chd').valueChanges.subscribe(this.filterAge.bind(this))
}
Reactive form instances like FormGroup and FormControl have a
valueChanges method that returns an observable that emits the latest
values. You can therefore subscribe to valueChanges to update instance
variables or perform operations.
source

register an angular form in a nested json

I am trying to convert a html form to a nested json.
These are my classes :
export class Config {
id: string;
name: string;
email: string;
lchart:ComponentLinechart;
}
export class ComponentLinechart {
name_linechart : String;
xAxis_linechart : String;
yAxis_linechart : String;
}
The formcomponent.ts:-
export class FormsComponent implements OnInit {
newConfig: Config = new Config();
constructor(private service : MyserviceService, private configservice:ConfigurationService) {
}
email = new FormControl('', [Validators.required, Validators.email]);
xAxisControl = new FormControl('', Validators.required);
yAxisControl = new FormControl('', Validators.required);
name_linechart = new FormControl('', Validators.required);
name = new FormControl('', Validators.required);
getConfig(): void {
this.configservice.getConfig()
.subscribe(data => this.configs = data );
}
createConfiguration(todoForm: NgForm): void {
this.configservice.createConfig(this.newConfig)
.subscribe(createconfig => {
todoForm.reset();
this.newConfig = new Config();
this.configs.unshift(createconfig)
});
}
The formcomponent.html :-
<form #todoForm="ngForm" (ngSubmit)="createConfiguration(todoForm)" novalidate>
<div class="example-container">
<mat-form-field appearance="fill">
<mat-label>Enter your name</mat-label>
<input matInput [(ngModel)]="newConfig.name" name="name" [formControl]="name" required>
</mat-form-field>
<br>
<mat-form-field appearance="fill">
<mat-label>Enter your email</mat-label>
<input matInput placeholder="pat#example.com" [(ngModel)]="newConfig.email" name="email"
[formControl]="email" required>
<mat-error *ngIf="email.invalid">{{getErrorMessage()}}</mat-error>
</mat-form-field>
<br>
<mat-form-field appearance="fill">
<mat-label>Name-linechart</mat-label>
<input matInput [(ngModel)]="newConfig.name_linechart" name="name_linechart"
[formControl]="name_linechart" required>
</mat-form-field>
<br>
<mat-form-field *ngIf = "sales" >
<mat-label>xAxis-linechart</mat-label>
<mat-select [(ngModel)]="newConfig.xAxis-linechart" name="xAxis-linechart"
[formControl]="xAxisControl" required>
<mat-option *ngFor="let field of fields" [value] = "field">
{{field}}
</mat-option>
</mat-select>
<mat-error *ngIf="xAxisControl.hasError('required')">Please choose a field</mat-error>
</mat-form-field>
<br>
<mat-form-field *ngIf = "sales" >
<mat-label>yAxis-linechart</mat-label>
<mat-select [(ngModel)]="newConfig.yAxis-linechart" name="yAxis-linechart"
[formControl]="yAxisControl" required>
<mat-option *ngFor="let field of fields" [value] = "field">
{{field}}
</mat-option>
</mat-select>
<mat-error *ngIf="yAxisControl.hasError('required')">Please choose a field</mat-error>
</mat-form-field>
Expected result :
{
"name": "adam",
"email": "adam#gmail.com",
"lchart": {
"name_linechart": "books",
"xAxis_linechart": "library",
"yAxis_linechart": "percentage"
}
}
But this is what I get :
{
"name": "adam",
"email": "adam#gmail.com",
"lchart": null
}
I tried to write newConfig.lchart.name_linechart in the formcomponent.html but it gives me the error :
TypeError : cannot read property name_linechart of undefined.
Foufa, NEVER, NEVER, NEVER, NEVER use [(ngModel)] and formControlName (or formControl) in the same tag. One is for template Form, another for ReactiveForms, see the docs
Well. You has an object that has properties, one of them is an object, so, you has a FormGroup with somes FormControls and one FormGroup, (again the docs)
myForm=new FormGroup({
name:new FormControl(),
email:new FormControl(),
lchart:new FormGroup({
name_linechart: new FormControl(),
xAxis_linechart: new FormControl(),
yAxis_linechart: new FormControl(),
})
})
And the .html
<form [formGroup]="myForm">
<!--see, under the formGroup, we using formControlName for the formControl-->
<input formControlName="name">
<input formControlName="email">
<!--when we has a FomgGroup, we use formGrpupName in a div-->
<div formGroupName="lchart">
<!--and formControlName under the div -->
<input formControlName="name_linechart">
<input formControlName="xAxis_linechart">
<input formControlName="yAxis_linechart">
</div>
</form>
<!--we can add, only for check-->
<pre>
{{myForm?.value|json}}
</pre>
Update as always, is util use a function that received an object and create the form
getForm(data:any)
{
data=data || { name:null,
email:null,
lchart:{
name_linechart:null,
xAxis_linechart:null,
yAxis_linechart:0
}
}
return new FormGroup({
name:new FormControl(data.name,Validator.required),
email:new FormControl(data.email,[Validator.required,Validators.emailValidator),
lchart:new FormGroup({
name_linechart: new FormControl(data.lchart.name_linechart),
xAxis_linechart: new FormControl(data.lchart.xAxis_linechart),
yAxis_linechart: new FormControl(data.lchart.yAxis_linechart),
})
}
And use as
myForm=this.getForm(data) //<--if we has an object "data"
//or
myForm=this.getForm(null) //if we want a empty form
I guess your [(ngModel)] binding wrong for name_linechart,xAxis_linechart,yAxis_linechart fields.
It should be
[(ngModel)]="newConfig.lchart.name_linechart"
[(ngModel)]="newConfig.lchart.xAxis_linechart"
[(ngModel)]="newConfig.lchart.yAxis_linechart"
change your constructor to-
constructor(private service : MyserviceService, private configservice:ConfigurationService) {
this.newConfig.lchart=new ComponentLinechart(); //add this line
}

Angular 6 show dropdown dependent selected option

I have two dropdown select option, but I'm struggling update second's selected option based on first one.
HTML
<form novalidate [formGroup]="editModuleForm" (ngSubmit)="onSubmitForm()">
<div align="center">
<mat-form-field>
<mat-select placeholder="Select Module" formControlName="moduleControl" required>
<mat-option *ngFor="let module of modules" [value]="module" (click)="popData()">
{{ module.title }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div *ngIf="editModuleForm.get('moduleControl').value" align="center">
<div align="center">
<mat-form-field>
<mat-select placeholder="Select Course" formControlName="courseControl">
<mat-option *ngFor="let course of courses" [value]="course.courseId" >
{{ course.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
Component
constructor(private putService: PutService, private getService: GetService,
private router: Router, private formBuilder: FormBuilder) {}
ngOnInit() {
this.getService.findAllModule().subscribe(modules => {
this.modules = modules;
});
this.getService.findAllCourses().subscribe(courses => {
this.courses = courses;
});
this.editModuleForm = this.formBuilder.group({
moduleControl: this.formBuilder.control(null),
courseControl: this.formBuilder.control(null)
});}
popData() {
this.editModuleForm.get('moduleControl').valueChanges.subscribe(
value => {
this.editModuleForm.controls['courseControl'].setValue(value.course);
console.log(value);
}
);}
After selecting an item in the first dropdown, I would like to default select module's course in the second dropdown and refresh after selecting another one.
You need subscribe changes on ngOnInit() no need to call click event
here's an example
ngOnInit() {
this.editModuleForm = this.formBuilder.group({
moduleControl: '',
courseControl: ''
});
this.popData();
}
popData() {
this.editModuleForm.controls['moduleControl'].valueChanges.subscribe(
value => {
this.editModuleForm.controls['courseControl'].setValue(value.id);
}
);
}
Stackblitz demo
I think the problem is you are calling this.editModuleForm.get('moduleControl').valueChanges in the click event, you actually want to call that in the ngOnInit. Its starting to listen to the value changes are the value has already changed!
Maybe try this:
constructor(private putService: PutService, private getService: GetService,
private router: Router, private formBuilder: FormBuilder) {}
ngOnInit() {
this.getService.findAllModule().subscribe(modules => {
this.modules = modules;
});
this.getService.findAllCourses().subscribe(courses => {
this.courses = courses;
});
this.editModuleForm = this.formBuilder.group({
moduleControl: this.formBuilder.control(null),
courseControl: this.formBuilder.control(null)
});
this.editModuleForm.get('moduleControl').valueChanges.subscribe(
value => {
this.editModuleForm.controls['courseControl'].setValue(value.course);
console.log(value);
}
}
You can get rid of the click event and the pop() method

Filter autocomplete Material. Some input form work like one input

can you help me please. I have some problem with Autocomplete Material.
I don't know what is the problem, I follow this tutorial: https://material.angular.io/components/autocomplete/overview
In component.ts
import { Component } from '#angular/core';
import { FormControl } from '#angular/forms';
import { Observable } from 'rxjs/Observable';
import { startWith } from 'rxjs/operators/startWith';
import { map } from 'rxjs/operators/map';
#Component({ selector: 'autocomplete-filter-example',
templateUrl: 'autocomplete-filter-example.html',
styleUrls: ['autocomplete-filter-example.css'] })
export class AutocompleteFilterExample {
myControl: FormControl = new FormControl();
myControl1: FormControl = new FormControl();
myControl2: FormControl = new FormControl();
options = [
'One',
'Two',
'Three' ];
options1 = [
'test',
'test2',
'test1' ];
options2 = [
'test3',
'test5',
'test10' ];
filteredOptions: Observable<string[]>;
filteredOptions1: Observable<string[]>;
filteredOptions2: Observable<string[]>;
ngOnInit() {
this.filteredOptions = this.myControl.valueChanges
.pipe(
startWith(''),
map(val => this.filter(val))
);
this.filteredOptions1 = this.myControl1.valueChanges
.pipe(
startWith(''),
map(val => this.filter1(val))
);
this.filteredOptions1 = this.myControl1.valueChanges
.pipe(
startWith(''),
map(val => this.filter1(val))
);
this.filteredOptions2 = this.myControl2.valueChanges
.pipe(
startWith(''),
map(val => this.filter2(val))
); }
filter(val: string): string[] {
return this.options.filter(option =>
option.toLowerCase().indexOf(val.toLowerCase()) === 0); }
filter1(value: string): string[] {
return this.options1.filter(option1 =>
option1.toLowerCase().indexOf(value.toLowerCase()) === 0); }
filter2(value: string): string[] {
return this.options1.filter(option1 =>
option1.toLowerCase().indexOf(value.toLowerCase()) === 0); }
}
Component.html
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one1" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option">
{{ option }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one2" aria-label="Number" matInput [formControl]="myControl1" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option1 of filteredOptions1 | async" [value]="option1">
{{ option1 }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="example-full-width">
<input type="text" placeholder="Pick one3" aria-label="Number" matInput [formControl]="myControl2" [matAutocomplete]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let option2 of filteredOptions2 | async" [value]="option2">
{{ option2 }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
My question is: Why input work like one and display only one array? In this link you can see my problem.
https://stackblitz.com/edit/angular-yw23zr-u25rqk?file=app%2Fautocomplete-filter-example.html
Please if have some idea, I want to help me. Thank you
You need to have different template reference for your different autocomplete.
your need <mat-autocomplete #auto="matAutocomplete"> / <mat-autocomplete #auto1="matAutocomplete"> and <mat-autocomplete #auto2="matAutocomplete">
and [matAutocomplete]="auto" [matAutocomplete]="auto1" [matAutocomplete]="auto2"
In your example, you use the reference #auto multiple times, so it keeps the last autocomplete as reference ( that why you see the same list three times).
Plus you have some typo in your example :
1/ your have this block twice
this.filteredOptions1 = this.myControl1.valueChanges
.pipe(
startWith(''),
map(val => this.filter1(val))
);
2/ your filter2 value is based upon this.value1 for filtering instead of this.option2
Here is the forked stackblitz