Angular - filtrowanie listy produktów na podstawie wybranej kategorii

0

Witam chciałbym w swojej aplikacji w angularze stworzyć navbar, który filtrował by moja listą produktów na podstawie wybranej kategorii. Wygląda to tak jak na tym zdjęciu: navbar.PNG
**Mój NavbarComponent: **

export class SortProductsComponent implements OnInit {
  categoriesList: Categories[];
  @Output()
  onFilterChange = new EventEmitter<any>();
  showFilters = true;
  sideShown = false;
  constructor(private categoriesService: CategoriesProductsService) { }

  ngOnInit() {
    this.displayCategories();
  }
  displayCategories() {
    this.categoriesService.getCategories().subscribe((data) => {
     this.categoriesList = data;

    });
  }
  onInputChange($event, filterbyCategory) {
    const change = $event.target.checked ? 1 : -1;
    this.onFilterChange.emit({
      filterbyCategory,
      isChecked: $event.target.checked,
      change
    });
    console.log(this.onFilterChange);
}
}

Metoda onInputChange zwraca prawidłowe dane np. po zaznaczeniu kategorii Smartfons zwraca następujące dane: Debugging.png, właściwości isChecked= true; change = 1;

**ProductComponent komponent rodzica: **

export class ProductComponent implements OnInit {
  listProduct: Products[];
  filteredProducts: any;
  @ViewChild('filtersComponent')
  filtersComponent: SortProductsComponent;
  constructor(protected productsService: CategoriesProductsService) { }

  ngOnInit() {
    this.displayProducts();

  }
  displayProducts() {
    this.productsService.getProducts().subscribe((data) => {
      this.listProduct = data;

      });
    }
 onFilterChange(data) {
  if (data.isChecked) {
  }
 }
}

Szablon HTML komponentu ProductComponent

<div class="d-flex" id="wrapper">
  <div  *ngIf="wrapper" class="col-xs-12 bg-light border-right" id="sidebar-wrapper">
    <div class="sidebar-heading">Sorting navbar</div>
    <app-sort-products  #filtersComponent (onFilterChange)='onFilterChange($event)' ></app-sort-products>
  </div>
  <div id="page-content-wrapper">
    <div class="container-fluid">
        <button class="btn btn-primary" id="menu-toggle" (click)="showHide()" >Sidebar</button>
              
        <div class="row row-eq-height">
            <div class="col-12 col-xs-6 col-sm-4 col-md-4  h-100   d-inline-block " *ngFor="let product of listProduct" >
              <h3 style="text-align: center">{{product.Name}}</h3>
              <img class="img-responsive"  style="max-width:150px;max-height:150px" src="{{product.Image}}">
              <p style="color: red">Price: {{product.Price}}PLN</p>
            </div>
          </div>
    </div>
  </div>
</div>

Klasy Categories i Product:

export class Categories {
  Id: number;
  Name: string;
  Product: Products[];
}

export class Products {
  Id: number;
  Name: string;
  Description: string;
  DetailedDescription: string;
  Price: number;
  IsNewProduct: boolean;
  PromotionalProduct: boolean;
  Image: string;
  CategoryId: number;
}

Nie wiem jak poprawnie stworzyć metodę która odbiera dane z komponetu dziecka, a następnie filtruje listę produktów na podstawie wybranej z checkbox listy kategorii.

0

Jeżeli chodzi o odbieranie danych z child component, to w parent component nie musisz miec ViewChild, a w HTMLu nie musisz mieć #filtersComponent. Wystarczy że nasłuchujesz na event, który emituje child component - tak jak w dokumentacji https://angular.io/guide/component-interaction#parent-listens-for-child-event W twoim przypadku wygląda to dobrze - czy parent component odbiera dane prawidłowo?
Jeżeli chodzi o filtrowanie to możesz sobie w parent component po pobraniu produktów przypisać je do 2 tablic - listProduct oraz filteredProduct. Następnie w metodzie onFilterChange filtrujesz tablicę filteredProduct i ją wyświetlasz.

0
Marek Urbanek napisał(a):

Jeżeli chodzi o odbieranie danych z child component, to w parent component nie musisz miec ViewChild, a w HTMLu nie musisz mieć #filtersComponent. Wystarczy że nasłuchujesz na event, który emituje child component - tak jak w dokumentacji https://angular.io/guide/component-interaction#parent-listens-for-child-event W twoim przypadku wygląda to dobrze - czy parent component odbiera dane prawidłowo?
Jeżeli chodzi o filtrowanie to możesz sobie w parent component po pobraniu produktów przypisać je do 2 tablic - listProduct oraz filteredProduct. Następnie w metodzie onFilterChange filtrujesz tablicę filteredProduct i ją wyświetlasz.

Zrobiłem coś takiego:

    ngOnInit() {
    this.displayProducts();
  }
  displayProducts() {
    this.productsService.getProducts().subscribe((data) => {
      this.listProduct = data;
      });
    }
    onFilterChange(data) {
        if (data.isChecked) {
          this.filteredProduct.push(data.filterbyCategory.Products);
          console.log(this.filteredProduct);
        }

filterProduct.PNG
Tylko nie wiem teraz jak filtrować te dane aby wyświetlały się z określonej zaznaczonej kategorii.

0

Możesz to zrobić np. w taki sposób:

displayProducts() {
    this.productsService.getProducts().subscribe((data) => {
      this.listProduct = data;
      this.filteredProduct = data
      });
    }

A w HTMLu ngFor zrobić po filteredProduct zamiast listProduct

0

Teraz wszystko działa tak jak należy

 ngOnInit() {
    this.displayProducts();
  }
  displayProducts() {
    this.productsService.getProducts().subscribe(product => {
      this.filteredProduct = product;
    });
    }
    onFilterChange(data) {
      if (data.isChecked) {
          for (let i = 0; i < data.filterbyCategory.Products.length; i++) {
          this.filteredProduct.push(data.filterbyCategory.Products[i]);
          }
        } else {
          this.filteredProduct =
          this.filteredProduct.filter(x => {
            return x.CategoryId !== data.filterbyCategory.Id; } );
        }
       }

1 użytkowników online, w tym zalogowanych: 0, gości: 1