I want to make an e-commerce Filter By Category in Angular

爷,独闯天下 提交于 2021-02-11 14:59:04

问题


I tried but, I guess I coded exactly opposite that what I wanted.

1. all-trades.component.html

<div
  fxLayout="row"
  fxLayout.lt-md="column"
  fxLayoutAlign="space-between start"
  fxLayoutAlign.lt-md="start stretch"
  *ngIf="crops$ | async"
>
  <div class="container-outer" fxFlex="20">
    <div class="filters">
      <section class="example-section">
        <span class="example-list-section">
          <h1>Select Crop</h1>
        </span>
        <span class="example-list-section">
          <ul>
            <li *ngFor="let filter of nameFilters$ | async">
              <mat-checkbox
                [checked]="filter.checked"
                (change)="onNameFilterChange(filter)"
              >
                {{ filter.name }}
              </mat-checkbox>
            </li>
          </ul>
        </span>
      </section>

      <section class="example-section">
        <span class="example-list-section">
          <h1>Select District</h1>
        </span>
        <span class="example-list-section">
          <ul>
            <li *ngFor="let filter of filteredDistrictCheckboxes$ | async">
              <mat-checkbox
                [checked]="filter.checked"
                (change)="onDistrictFilterChange(filter)"
              >
                {{ filter.name }}
              </mat-checkbox>
            </li>
          </ul>
        </span>
      </section>
    </div>
  </div>
  <div class="content container-outer" fxFlex="80">
    <mat-card
      class="crop-card"
      style="min-width: 17%"
      *ngFor="let crop of filteredCrops$ | async"
      [hidden]="!crop.checked"
    >
      <a [routerLink]="[crop.name]">
        <mat-card-header>
          <img
            mat-card-avatar
            class="example-header-image"
            src="/assets/icons/crops/{{ crop.name }}.PNG"
            alt="crop-image"
          />
          <mat-card-title>{{ crop.name }}</mat-card-title>
          <mat-card-subtitle>100 Kgs</mat-card-subtitle>
        </mat-card-header>
      </a>
      <mat-card-content>
        <p>PRICE</p>
      </mat-card-content>
      <mat-card-content>
        <p>{{ crop.district }}</p>
      </mat-card-content>
    </mat-card>
  </div>
</div>

2.all-trades.component.ts

import { OnInit } from '@angular/core';
import { Component } from "@angular/core";
import { BehaviorSubject, combineLatest, Observable } from "rxjs";
import { map, shareReplay, switchMap, tap } from "rxjs/operators";
import { Crop } from 'src/app/shared/crop.model';
import { CropService } from '../crop.service';

// dialog box
interface Filter {
  name: string;
  checked: boolean;
}

@Component({
  selector: 'app-all-trades',
  templateUrl: './all-trades.component.html',
  styleUrls: ['./all-trades.component.css'],
})
export class AllTradesComponent implements OnInit {

  crops$: Observable<Crop[]>;
  filteredCrops$: Observable<Crop[]>;
  nameFilters$ = new BehaviorSubject<Filter[]>([]);
  districtFilters$ = new BehaviorSubject<Filter[]>([]);
  filteredDistrictCheckboxes$: Observable<Filter[]>;

  constructor(private cropService: CropService) { }
  ngOnInit(): void {
    this.crops$ = this.cropService.getAllCrops().pipe(
      tap(crops => {
        const names = Array.from(new Set(crops.map(crop => crop.name)));
        this.nameFilters$.next(
          names.map(name => ({ name, checked: true } as Filter))
        );
        const dictricts = Array.from(new Set(crops.map(crop => crop.district)));
        this.districtFilters$.next(
          dictricts.map(name => ({ name, checked: true } as Filter))
        );
      }),
      shareReplay(1)
    );
    this.filteredCrops$ = combineLatest(
      this.crops$,
      this.nameFilters$,
      this.districtFilters$
    ).pipe(
      map(
        ([crops, nameFilters, districtFilters]: [
          Crop[],
          Filter[],
          Filter[]
        ]) => {
          let items = [...crops];
          items = items.filter(item => {
            const associatedNameFilter = nameFilters.find(
              filter => filter.name === item.name
            );
            const associatedDistrictFilter = districtFilters.find(
              filter => filter.name === item.district
            );
            return (
              associatedNameFilter.checked && associatedDistrictFilter.checked
            );
          });
          return items;
        }
      )
    );

    this.filteredDistrictCheckboxes$ = this.nameFilters$.pipe(
      switchMap((nameFilters: Filter[]) => {
        return this.crops$.pipe(
          map(crops => {
            const enabledNames = nameFilters
              .filter(item => item.checked)
              .map(filter => filter.name);
            const enabledDistricts = Array.from(
              new Set(
                crops
                  .filter(crop => enabledNames.includes(crop.name))
                  .map(crop => crop.district)
              )
            );
            const result = this.districtFilters$.value.filter(item =>
              enabledDistricts.includes(item.name)
            );
            return result;
          })
        );
      })
    );
  }
  onChange(event, index, item) {
    item.checked = !item.checked;
    console.log(index, event, item);
  }

3. crop.data.ts

import { Crop } from "./crop.model";

export const CROPS: Crop[] = [
    {
        name: "Rice", // I want this Rice
        checked: true,
        district: "Thane",
        subCategory: [
            {
                id: 1,
                name: "Basmati",
                checked: true
            },
            {
                id: 2,
                name: "Ammamore",
                checked: true
            }
        ]
    },
    {
        name: "Rice", // also this one but on clicking on single Checkbox with name as Rice
        checked: true,
        district: "Nashik",
        subCategory: [
            {
                id: 1,
                name: "Basmati",
                checked: true
            },
            {
                id: 2,
                name: "Ammamore",
                checked: true
            }
        ]
    },
    {
        name: "Wheat",
        checked: true,
        district: "Nashik",
        subCategory: [
            {
                id: 1,
                name: "Durum",
                checked: true
            },
            {
                id: 2,
                name: "Emmer",
                checked: true
            }
        ]
    },
    {
        name: "Barley",
        checked: true,
        district: "Ratnagiri",
        subCategory: [
            {
                id: 1,
                name: "Hulless Barley",
                checked: true
            },
            {
                id: 2,
                name: "Barley Flakes",
                checked: true
            }
        ]
    },
    {
        name: "Barley",
        checked: true,
        district: "Thane",
        subCategory: [
            {
                id: 1,
                name: "Hulless Barley",
                checked: true
            },
            {
                id: 2,
                name: "Barley Flakes",
                checked: true
            }
        ]
    }
];

4. crop.model.ts

export class Crop {
    name: string;
    checked: boolean;
    district: string
    subCategory: Subcategory[];
}

export class Subcategory {
    id: number;
    name: string;
    checked: boolean;
}


Here I am sharing my output result

enter image description here

I want output like this

enter image description here

As you can see on left hand side there is filter, when someone check that checkboxes the result display according to that. But in my scenario all the checkbox is selected by default. i want to make it working excatly like e-commerece filter. Please share code on stackblitz

来源:https://stackoverflow.com/questions/64981058/i-want-to-make-an-e-commerce-filter-by-category-in-angular

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!