Angular 2 具有反应式表单的多类别复选框过滤器

Angular 2 Multiple Category Checkbox Filter With Reactive Form

我正在尝试使用 2 个不同的类别(希望更多)做一个更复杂的(对我来说)过滤器,frameBrand 和 frameColor。我想过滤到特定品牌,然后使用这些结果过滤颜色,直到我有更多 specific/narrow 搜索。我正在努力筛选 2 个类别

在下面的示例 JSON 中,我想单击品牌复选框以获取“anne klein”镜框,然后单击颜色复选框“棕色”以查看“anne klein - brown”镜框。 2 个复选框,每个复选框来自不同的“类别”。理想情况下,我可以将其扩展为使用其他类别,例如价格复选框。我已经使用 Whosebug 通过 .filter 获得了我所处的位置,但是使用 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]
    }
  ]
}

在我的 TS 文件中,我有 3 个函数,filterFramesByBrand、filterFramesByColor 和 filterResults。当 (change)="filterFramesByBrand($event)" 发生时,我从品牌和颜色中取出选中的复选框并将它们推送到我的 formGroup 中的不同数组。然后我 运行 filterResults 函数,我试图让魔法发生。我已经按预期过滤了品牌,但混合使用这两个类别(品牌和颜色)让我感到困惑。我已经注释掉了我的 filterResults 函数的颜色部分,因为出于某种原因它不像品牌部分那样工作。

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;
    }
  }

最后:这是我的 StackBlitz 的 link - https://stackblitz.com/edit/angular-ivy-product-filters?file=src%2Fapp%2Fproduct-filter.ts 我认为通过一些关于 .filter 函数的指导我可以解决这个问题。感谢您的帮助或建议。

我会简化你的逻辑。 与其使用 FormArraysFormGroup 执行此操作(除非这不是要求),这里最好的方法是创建 FilterComponent 接受作为输入示例对象 type CheckboxFilter = { name: string, isChecked: boolean }。如果需要,您可能可以添加 id。 创建后将 Output 添加到您的 FilterComponent。 现在您添加到 BrandChangedColorChanged 的处理程序。基于此,您可以存储选定的滤镜并将它们应用到您的相框上。

这甚至可以让您使其更具反应性。 你可以为 BrandColor 贴上 BehaviourSubject<string[]>,一旦发生事件你就可以操纵主题。 稍后只有 combainLatest 来自 JSON 文件或 API 的帧,然后像这样应用:

combineLatest([frames$, brands$, colors$]).pipe(filter([frames, brands, colors]) => ...) 

这里正在工作stackblitz