0

I have application which stores a list of cars.I wanted to add Search property into my project.I decided to use pipe and ngModel for my searchBox in order to do that.I have an array of those cars being listened by subscribe() whenever anything changes on it.In the pipe,I have const obj variable and it filters the array according to ngModel from component as I wish.But angular gives error and says ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined: [object Object],[object Object],[object Object]'. Current value: 'undefined: '. .I guess its undefined at first thats why its happening.But I added if block in order to check undefined or not, not to get this error .Here's my components and pipe below

Car-List Component.html

  <form class="example" style="margin:auto;max-width:200px">
    <input [(ngModel)]="nameBrand" type="text" placeholder="Search.." name="search2">
  </form>
  <div class="row">
    <div class="col-xs-12">
      <app-car-item
        *ngFor="let carEl of cars | orderName:nameBrand ;let i = index"
        [car]="carEl"
        [index]="i"
        >
      </app-car-item>
    </div>
  </div>

OrderPipe.ts

@Pipe({
  name: 'orderName',
})
export class OrderNamePipe implements PipeTransform{
  constructor(private carService:CarService)
  {

  }
  transform(value: any, arg1: any) 
   {       
      const obj = this.carService.getCars().filter(s => s.brand.includes(arg1));      
      if(obj)
      {
           this.carService.setCars(obj);
     }
    }
  }

Car-list.component.ts

  ngOnInit() {
    this.subscription=this.carService.carsChanged
    .subscribe(
     (cars:Car[])=>
     {
       this.cars=cars;
     }
    );
    this.cars = this.carService.getCars();
    }

Car.Service.ts

        export class CarService
    {
       carsChanged=new Subject<Car[]>();
       private cars: Car[]=[
            new Car(
               'Dodge Viper SRT10',
               'Coupe',
               2017,
               645,
               600,
               'Gasoline',
               'Used',
               'http://cdn-ds.com/stock/2010-Dodge-Viper-SRT10-ACR-Ltd-Avail-Akron-OH/seo/ECL2585-1B3AZ6JZ6AV100278/sz_88264/b22eddbbf045c389bd39e4ede1328f13.jpg',
               970000
           ),
           new Car(
            'Chevrolet Camaro',
            'Coupe',
            2012,
            432,
            600,
            'Gasoline',
            'Used',
            'https://carimages.com.au/MdzpzcZ7iNNuMu7RlH3Eg5t30CM=/fit-in/800x540/filters:stretch(FFFFFF)/vehicles/used/2018/CHEVROLET/CAMARO/2018-CHEVROLET-CAMARO-used-78-JWF447-1.jpg',
            274000
        ),
        new Car(
            'Bentley Continental-GT',
            'Coupe',
            2018,
            601,
            489,
            'Gasoline',
            'New',
            'https://cdn1.autoexpress.co.uk/sites/autoexpressuk/files/2017/11/4bentleycontinentalgt.jpg',
            4150000
        ) 
       ]
       constructor()
       {}
       setCars(cars: Car[]) {
        this.cars = cars;
        this.carsChanged.next(this.cars.slice());
 getCars()
   {
    return this.cars;
   }
      }

Car-Model.ts

export class Car{
    public brand:string;
    public type:string;
    public year:number;
    public bhp:number;
    public torque:number;
    public fuel:string;
    public condition:string;
    public imageUrl:string;
    public price:number;

    constructor(brand:string,type:string,year:number,bhp:number,torque:number,fuel:string,condition:string,imageUrl:string,price:number)
    {
        this.brand=brand;
        this.type=type;
        this.year=year;
        this.bhp=bhp;
        this.torque=torque;
        this.fuel=fuel;
        this.condition=condition;
        this.imageUrl=imageUrl;
        this.price=price;
    }
}
5
  • what if youn try to put a NgIf on your <div class="col-xs-12" *ngIf="cars && cars.length"> <app-car-item *ngFor="let carEl of cars | orderName:nameBrand ;let i = index" [car]="carEl" [index]="i" > </app-car-item> </div> Commented Sep 6, 2019 at 7:08
  • can you please update getCars() method and Car[] ? Commented Sep 6, 2019 at 7:21
  • @federicoscamuzzi that throws me this error : ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: 3'. Current value: 'ngIf: 0' Commented Sep 6, 2019 at 7:24
  • @piyushjain I did Commented Sep 6, 2019 at 7:26
  • is it a @input() prop ? Commented Sep 6, 2019 at 7:39

1 Answer 1

1

I don't think its a good way to use the data from the service inside your pipe. Try this pipe instead,

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

@Pipe({
    name: 'orderName'
})

@Injectable()
export class OrderNamePipe implements PipeTransform {
    transform(items: any[], field: string, value: string): any[] {
        if (!items) {
            return [];
        }
        if (!field || !value) {
            return items;
        }
        return items.filter(singleItem => singleItem[field].toLowerCase().includes(value.toLowerCase()));
    }
}

This way, your pipe is reusable. Change your template to,

<app-car-item
    *ngFor="let carEl of cars | orderName : 'brand' : nameBrand ;let i = index"
    [car]="carEl"
    [index]="i"
    >
</app-car-item>

The 'brand' is specified since you need to filter based on that field.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for your interest.I applied similar approach but there's a problem here.For example before search any brand when you click any car from the list in URL it returns cars/1 for example(Here in the image you can see i.ibb.co/kKNtFN1/cars-1.jpg).But after search if I select the on the list(Camaro in this example again),that returns id:0 Dodge Viper (i.ibb.co/XyVfdcn/Cars-2.jpg ) . Thats why Im trying to update the cars in the service by setCar() method
@TimuçinÇiçek Are you sure that's a correct implementation? You are using the index to identify each car. That's not a good practice I would recommend adding a unique ID for each car and on selecting one, use it to query the details.
yeah Im working on it but I couldn't do that.Also added Id property for each element in the model
After added id property inside my model.I changed index binding with model id ,instead URL index so problem solved thanks a lot here what I changed <app-car-item *ngFor="let carEl of cars | orderName : 'brand' : nameBrand ;let i = index" [car]="carEl" [index]="carEl.id" >

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.