lundi 23 novembre 2020

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

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)"
              >
                
              </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)"
              >
                
              </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/.PNG"
            alt="crop-image"
          />
          <mat-card-title></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></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




Aucun commentaire:

Enregistrer un commentaire