0

I'm trying to search through a list of cars (which have a make, model, price, and other values) and compare it to the car I am searching for on my form.

I know how to do it where I compare the two cars exactly, but I'm not sure how to filter it when I, for example, only want to search by make and show all the cars by the same make (but not worry about the other values since nothing else was selected).

I've tried using the lowdash ._isEqual(), which worked if the two objects are exactly the same. But, I have no idea how to do it if I only want to search by a certain make, or only a certain year, or something like that.

app.component.ts

export class AppComponent {
  cars:Car[];
  title = 'car-dealership';

  constructor(private carsService:CarsService) {}

  searchCars(car:Car) {
    this.carsService.getAllCars().subscribe(resp => {
      this.cars = resp;
      this.cars.filter(c => {
        //do something
      })
    })
  }
}

input-form.component.ts

export class InputFormComponent implements OnInit {
  @Output() searchCars: EventEmitter<any> = new EventEmitter();

  make:string;
  year:number;
  color:string;
  sunRoof = false;
  fourWheel = false;
  lowMiles = false;
  powerWindows = false;
  navigation = false;
  heatedSeats = false;
  price:number;

  constructor() { }

  ngOnInit() {
  }

  onSubmit() {
    const selectedCar = {
      color: this.color,
      hasHeatedSeats: this.heatedSeats,
      hasLowMiles: this.lowMiles,
      hasNavigation: this.navigation,
      hasPowerWindows: this.powerWindows,
      hasSunroof: this.sunRoof,
      isFourWheelDrive: this.fourWheel,
      make: this.make,
      price: Number(this.price),
      year: Number(this.year)
    }
    console.log('form submitted with:', selectedCar);
    this.searchCars.emit(selectedCar);
  } 
}

cars.service.ts

export class CarsService {

  constructor() {}

  getAllCars() {
    return of(Cars);
  }
}
Annah Isenberg
  • 147
  • 1
  • 10
  • Did you look at the docs for `Array.prototype.filter()`? Didn't help to make an attempt? :) [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) – AT82 Jun 19 '19 at 14:58
  • Possible duplicate of [How to filter object array based on attributes?](https://stackoverflow.com/questions/2722159/how-to-filter-object-array-based-on-attributes) – Vlad274 Jun 19 '19 at 15:02

3 Answers3

0

The filter method just needs to return if the item should be included - if it returns true (or any other "truthy" value) the item is included, and excluded otherwise.

  searchCars(car:Car) {
    this.carsService.getAllCars().subscribe(resp => {
      this.cars = resp.filter(c => {
        return c.make === this.make; // Or whatever complicated logic you want to use
      });
    });
  }

From your comment, I understand that you need to check two things: 1) should this criteria be used and 2) does the item match the criteria.

So, let's code that!

  searchCars(car:Car) {
    this.carsService.getAllCars().subscribe(resp => {
      this.cars = resp.filter(c => {
        // First, check if the criteria should be used
        if (this.make && this.make.length > 0) {
          return c.make === this.make;
        }
        // Return a default value if the criteria isn't being used
        return true;
      });
    });
  }

Ok, that's great. But what if it needs to match zero, one, or TWO conditions?

Well, we're going to use a "trick" or "pattern" called the "early return". Instead of checking that it matches ALL conditions and returning true, we'll check if it doesn't match EACH condition and return false:

  searchCars(car:Car) {
    this.carsService.getAllCars().subscribe(resp => {
      this.cars = resp.filter(c => {
        // First, check if the criteria should be used
        if (this.make && this.make.length > 0) {
          // Then, check if it doesn't match
          if (c.make !== this.make) {
            // Early return, it doesn't matter what the other checks say
            // we know this shouldn't be included.
            return false;
          }
        }
        // First, check if the criteria should be used
        if (this.color && this.color.length > 0) {
          // Then, check if it doesn't match
          if (c.color !== this.color) {
            // Early return, it doesn't matter what the other checks say
            // we know this shouldn't be included.
            return false;
          }
        }
        // Repeat for all conditions you need to look at

        // Return a default value. If the code gets here it means either:
        // 1) no conditions are applied
        // 2) it matches all relevant conditions
        return true;
      });
    });
  }
Vlad274
  • 6,514
  • 2
  • 32
  • 44
  • But the thing is, is that I don't know what I want to filter by because it all depends on what the user wants to filter by. If they want to filter by make, then I want it to filter by make, if they want to filter by make AND year, then I want it to filter by make AND year. If they want to filter by color, year, make, and four wheel drive, then I want them to be able to do that. I just don't know how to do that.... – Annah Isenberg Jun 19 '19 at 15:17
  • @AnnahI I have updated the answer with a more detailed breakdown of how you can code that behavior. – Vlad274 Jun 19 '19 at 15:31
  • Thank you so much! I am going to try this now! :) Also, I know a Vlad who is a consultant and works with Angular...haha too funny. – Annah Isenberg Jun 19 '19 at 15:40
0

Try the below

this.cars.filter(c => {
        return c.make == this.make // You can have multiple conditions here
})

Filter method returns items in a new array which satisfies the condition.

Sathishkumar Rakkiyasamy
  • 3,509
  • 2
  • 30
  • 34
  • But the thing is, is that I don't know what I want to filter by because it all depends on what the user wants to filter by. If they want to filter by make, then I want it to filter by make, if they want to filter by make AND year, then I want it to filter by make AND year. If they want to filter by color, year, make, and four wheel drive, then I want them to be able to do that. I just don't know how to do that.... – Annah Isenberg Jun 19 '19 at 15:16
0

You only need to tell filter function what condition you want to check in your array, and it will return each element your condition become true, for example, if you want to filter by make:

this.cars.filter(c => {
    c.make === 'SOME_MAKE'
});

You can also add multiple filters:

this.cars.filter(c => {
    c.make === 'SOME_MAKE' && c.year === 2015  // Filtering by make and year
});
Ivan Zhen
  • 1
  • 3
  • But the thing is, is that I don't know what I want to filter by because it all depends on what the user wants to filter by. If they want to filter by make, then I want it to filter by make, if they want to filter by make AND year, then I want it to filter by make AND year. If they want to filter by color, year, make, and four wheel drive, then I want them to be able to do that. I just don't know how to do that.... – Annah Isenberg Jun 19 '19 at 15:16
  • 1
    In that case you must implement some type of control element allowing users to select their own filters (radiobuttons, checkboxes...) and you to get them in your code by [data binding](https://angular.io/guide/template-syntax). Then, you only apply filters based on user preferences. Hope it helps you. – Ivan Zhen Jun 19 '19 at 15:28