Angular 2 Multiple Category Checkbox Filter With Reactive Form

  angular, categories, checkbox, filter, javascript

I’m trying to do a more complex (for me) filter with 2 different categories (hopefully more), frameBrand & frameColor. I want to filter down to a specific brand, then use those results to filter colors until I have a more specific/narrow search. I’m struggling with filtering 2 categories

With my example JSON below, I’d like to click a brand checkbox to get "anne klein" frames then click a color checkbox "brown" to view the "anne klein – brown" frame. 2 checkboxes each from different "categories". Ideally, I’d be able to expand this to use other categories, like checkboxes for price. I’ve used StackOverflow to get where I’m at with .filter but haven’t seen much with multiple categories and checkboxes using Angular.

{
  "frames": [
    {
      "frameBrand": "altair",
      "frameColor": "Black",
      "frameId": 1,
      "frameName": "A5052",
      "releaseDate": "05-01-2021",
      "framePrice": 25,
      "frameDescription": "this is an altair frame.",
      "imageUrl": "/assets/images/frames/ALO/A5052/A5052_001_LG_01.jpg",
      "categories": [1]
    },
    {
      "frameBrand": "anne klein",
      "frameColor": "Ruby",
      "frameId": 2,
      "frameName": "AK5091",
      "releaseDate": "05-01-2021",
      "framePrice": 45,
      "frameDescription": "this is an anne klein frame.",
      "imageUrl": "/assets/images/frames/AKO/AK5091/AK5091_610_LG_01.jpg",
      "categories": [2]
    },
    {
      "frameBrand": "anne klein",
      "frameColor": "Brown",
      "frameId": 3,
      "frameName": "AK5090",
      "releaseDate": "05-01-2021",
      "framePrice": 45,
      "frameDescription": "this is an anne klein frame.",
      "imageUrl": "/assets/images/frames/AKO/AK5090/AK5090_200_LG_01.jpg",
      "categories": [2]
    },
    {
      "frameBrand": "bebe",
      "frameColor": "Silver",
      "frameId": 4,
      "frameName": "BB5192",
      "releaseDate": "05-01-2021",
      "framePrice": 40,
      "frameDescription": "this is an bebe frame.",
      "imageUrl": "/assets/images/frames/BBO/BB5192/BB5192_001_LG_01.jpg",
      "categories": [3]
    }
  ]
}

In my TS file I have 3 functions, filterFramesByBrand, filterFramesByColor and filterResults. I take the checked checkboxes from brands and colors and push them to different array’s in my formGroup when (change)="filterFramesByBrand($event)" occurs. Then I run the filterResults function where I’m trying to make the magic happen. I’ve gotten the brands to filter as expected but mixing the 2 categories (brands and colors) has me stumped. I’ve commented out the color section of my filterResults function because it’s not working like the brands section for some reason.

checkboxForm: FormGroup;

constructor(private fb: FormBuilder) {}

ngOnInit() {
  this.checkboxForm = this.fb.group({
    brandCheckArray: this.fb.array([]),
    colorCheckArray: this.fb.array([])
  });
}


filteredFrames: IFrames[] = [...this.frames];

  filterFramesByBrand(category) {
    const brandCheckArray: FormArray = this.checkboxForm.get(
      "brandCheckArray"
    ) as FormArray;

    if (category.target.checked) {
      brandCheckArray.push(new FormControl(category.target.value));
    } else {
      let i: number = 0;
      brandCheckArray.controls.forEach((item: FormControl) => {
        if (item.value == category.target.value) {
          brandCheckArray.removeAt(i);
          return;
        }
        i++;
      });
    }
    this.filterResults();
  }

  filterFramesByColor(category) {
    const colorCheckArray: FormArray = this.checkboxForm.get(
      "colorCheckArray"
    ) as FormArray;

    if (category.target.checked) {
      colorCheckArray.push(new FormControl(category.target.value));
    } else {
      let i: number = 0;
      colorCheckArray.controls.forEach((item: FormControl) => {
        if (item.value == category.target.value) {
          colorCheckArray.removeAt(i);
          return;
        }
        i++;
      });
    }
    this.filterResults();
  }

  filterResults() {
    this.filteredFrames = this.frames.filter(el => {
      let frameBrandEl = el.frameBrand
        .split(" ")
        .join("")
        .toLowerCase();
      // let frameColorsEl = el.frameColor
      //   .split(" ")
      //   .join("")
      //   .toLowerCase();

      let brandsChecked = this.checkboxForm.get("brandCheckArray").value;
      // let colorsChecked = this.checkboxForm.get("colorCheckArray").value;

      var fixCheckedBrands = brandsChecked.map(v =>
        v
          .split(" ")
          .join("")
          .toLowerCase()
      );
      // var fixCheckedColors = colorsChecked.map(v =>
      //   v
      //     .split(" ")
      //     .join("")
      //     .toLowerCase()
      // );

      console.log(frameBrandEl);
      // console.log(frameColorsEl);

      console.log(fixCheckedBrands);
      // console.log(fixCheckedColors);

      return frameBrandEl.includes(fixCheckedBrands);
      // return frameColorsEl.includes(fixCheckedColors);
    });

    // if there are no checked checkboxes - show all
    if (this.checkboxForm.value.brandCheckArray.length === 0) {
      this.filteredFrames = this.frames;
    }
  }

Finally: here is a link to my StackBlitz – https://stackblitz.com/edit/angular-ivy-product-filters?file=src%2Fapp%2Fproduct-filter.ts I think with a bit of guidance on the .filter function I could figure this out. Thanks for any help or suggestions.

Source: Ask Javascript Questions

LEAVE A COMMENT