【问题标题】:How to filter categories in Angular 9如何在 Angular 9 中过滤类别
【发布时间】:2020-08-28 05:21:05
【问题描述】:

我想在网上商店中按类别进行过滤。实际上我坚持使用 Mosh 的教程,因为我在浏览器或命令提示符中没有错误消息,但没有任何内容被过滤甚至显示。我是 Angular 和/或 typescript 的绝对初学者,所以请善待^^ 我试图自己解决这个问题已经很久了,但它不起作用。请帮帮我。

这是我的代码:

products.component.ts:

export class ProductsComponent {

 products: Product[]= [];
 filteredProducts: Product[] = [];
categories$: Observable<any>;
category: string;
products$: Observable<any>;


 constructor(
    route: ActivatedRoute,
    productService: ProductService, 
    categoryService: CategoryService) {
    this.filteredProducts;

productService.getAll().subscribe (products => this.products);



//Shows Categories in View
    this.categories$ = categoryService.getAll();
    route.queryParamMap.subscribe(params => {
      this.category = params.get('category');
      this.categories$.subscribe(res => console.log (res)); //Console.log  5 Categories Observable



      //Setting the filtered Products Array
      this.filteredProducts = (this.category) ? 
       this.products.filter(p => {
         return p.category === this.category;
       }) : 
      this.products;
      console.log(this.filteredProducts); // Console.log FilteredProducts Array
    });

   }

 }

products.component.html:

<div class="row">
  <div class="col-3">
    <div class="list-group">


      <!-- Bei queryParams c.name auswählbare Kategorien / bei c.key nicht sowie bei c.$key nicht-->
      <a *ngFor="let c of categories$ | async "
      routerLink= "/"
      [queryParams]="{ category: c.name }"  
       class="list-group-item list-group-item-action"
       [class.active]="category === c.name">
        {{ c.name }}
      </a>
    </div>  
  </div>
  <div class="col-9">
    <div class="row">
      <ng-container *ngFor="let product of filteredProducts ; let i = index">
        <div class="col">
          <div class="card" style="width: 15rem;">
          <img [src]="product.imageUrl" class="card-img-top" alt="Card image cap">
          <div class="card-body">
            <h5 class="card-title">{{ product.title }}</h5>
            <p class="card-text">{{ product.price | currency: 'EUR' }}</p>
            <a href="#" class="btn btn-primary">Add to Cart</a>
          </div>
        </div>
      </div>
      <div *ngIf="(i + 1) % 2 === 0" class="w-100"></div>
      </ng-container>
    </div>
  </div>
</div>

【问题讨论】:

  • this.category 设置是否正确?你有控制台记录吗?
  • 我在控制台记录了 this.category,它显示了正确的点击类别。你是这个意思吗?

标签: javascript angular typescript filter


【解决方案1】:

最新版本 angular 的正确分析器是

products.component.ts:

import { switchMap } from 'rxjs/operators';
import { Product } from './../models/product';
import { Categorie } from './../models/categorie';
import { ActivatedRoute } from '@angular/router';
import { ProductService } from './../product.service';
import { Component, OnInit } from '@angular/core';
import { CategoryService } from '../category.service';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent {

products: Product[]= [];
filteredProducts: Product[] = [];
categories$: Observable<any>;
category: string;
products$: Observable<any>;

  constructor(
    route:ActivatedRoute,
    productService:ProductService, 
    categoryService:CategoryService) {
   productService
   .getAll().pipe(
   switchMap(products=>{
     this.products = products;
     return route.queryParamMap;
   }))
   .subscribe(params =>{
     this.category =params.get('category');
     this.filteredProducts =(this.category)?
     this.products.filter(p=>p.category === this.category):
     this.products;
   });`enter code here`
this.categories$ = categoryService.getAll();

     }

    }

【讨论】:

    【解决方案2】:

    解决方案很简单>_

    这个:

    <a *ngFor="let c of categories$ | async" 
        routerLink="/"
        [queryParams]="{ category: c.key }"
        class="list-group-item list-group-item-action"
        [class.active] = 'category === c.key'
        >
        {{ c.payload.val().name }}
    </a>
    

    到:

    <a *ngFor="let c of categories$ | async" 
        routerLink="/"
        [queryParams]="{ category: c.payload.val().name }"
        class="list-group-item list-group-item-action"
        [class.active] = 'category === c.payload.val().name'
        >
        {{ c.payload.val().name }}
    </a>
    

    【讨论】:

      【解决方案3】:

      过滤部分存在问题,当您要根据类别过滤产品时,实际上并没有过滤。原因是因为您的程序没有在 p.category 中获取产品类别。因为您使用的是最新的 Angular 和最新的 Firebase。所以你应该使用p.payload.val().category。然后它将您的类别与 this.category 进行比较。

      试试给定的代码

      productService.getAll().pipe(switchMap(products => {
          this.products = products;
          return route.queryParamMap;
        }))
            .subscribe(params => {
            this.category = params.get('category');
            this.filterProducts = (this.category) ?
            this.products.filter(p => (p.payload.val().category)===this.category) :
            this.products;
          });
      

      【讨论】:

        【解决方案4】:

        这里productService.getAll()方法从API获取数据需要一些时间,但是route.queryParamMap会立即执行,而这个observable被订阅this.products对象会是空的,这就是它无法过滤的原因。您还没有在订阅中初始化this.products = products。 要解决所有这些问题,您可以按如下方式实现:

            export class ProductsComponent {
        
             products: Product[]= [];
             filteredProducts: Product[] = [];
            categories$: Observable<any>;
            category: string;
            products$: Observable<any>;
        
        
             constructor(
                route: ActivatedRoute,
                productService: ProductService, 
                categoryService: CategoryService) {
                this.filteredProducts = [];
        
        
                //Shows Categories in View
                this.categories$ = categoryService.getAll();
                route.queryParamMap.subscribe(params => {
                  this.category = params.get('category');
                    });
        
        
            productService.getAll().subscribe (products => {
                           this.products = products;
                                     //Setting the filtered Products Array
                           this.filteredProducts = (this.category) ? 
                           this.products.filter(p => {
                              return p.category === this.category;
                           }) : this.products;
                           console.log(this.filteredProducts); // Console.log FilteredProducts Array
        }); 
               }
        
             }
        

        这就是我在 console.log 中得到的结果,如下所示: productService.getAll().subscribe (products => { console.log(products); this.products = products;});

        并在 CMD 中:

        【讨论】:

        • 谢谢,但初始化 this.products = products 时出现错误。错误信息是:键入'{ $key: string; $值:未知; }[]' 不可分配给类型 'Product[]'。输入 '{ $key: string; $值:未知; }' 缺少“产品”类型的以下属性:标题、价格、类别、imageUrlts(2322)
        • @FloOmega 你能显示productService.getAll() 方法给出的响应吗,存在类型差异。
        • 这将是响应:(方法) ProductService.getAll(): Observable
        • @FloOmega,你会从哪里得到products?,你已经使用了this.products数组,但是没有提到你从哪个服务得到这个,它在$value对象中吗?
        • 我以为我是通过 Product as an Array 接口获取产品的。这是我在 product.service.ts 中的 getAll(): getAll(){ return this.db.list('products') .snapshotChanges() .pipe(map(changes => changes.map(c=>({ $key: c.payload.key, $value: c.payload.val() }))));这就是我的界面:导出界面产品{标题:字符串价格:数字;类别:字符串;图像网址:字符串; }
        【解决方案5】:

        嗯,有一些错误,首先是你有

        productService.getAll().subscribe (products => this.products);
        

        必须是

        productService.getAll().subscribe (products => this.products=products);
        

        但这不起作用,因为是异步调用。

        因此,首先更改您的 productService“缓存”产品。您的服务喜欢

        products:any[]
        getAll()
        {
            return products?of(product):
                   this.httpClient.get("your-url").pipe(
                      tap(res=>this.products=res;
                   )
        }
        

        我们使用来自 'rxjs' 的 of 和来自 'rxjs/operators' 的 tap

        这使得 getProducts 返回一个 Observable 产品。第一次调用,“产品”是未定义的,所以返回httpClient.get的响应。 procuts的tap make得到值,所以第二次被称为变量products被使用。

        第二个错误是使用“构造函数”使用 ngOnInit 订阅 route.queryParamMap。

        ngOnInit()
        {
           this.route.queryParamMap.subscribe(params => {
              this.category = params.get('category');
        
              //here you get all the products
              this.productService.getAll().subscribe (
                 products => this.products=products);
                 //Setting the filtered Products Array
                 this.filteredProducts = (this.category) ? 
                     this.products.filter(p => {
                      return p.category === this.category;
                 }) : 
                 this.products;
                 console.log(this.filteredProducts); // Console.log FilteredProducts Array
              });
        }
        

        嗯,另一种方法是使用 switchMap 并使过滤产品成为可观察的(然后我们使用过滤产品$ | async)

           this.filteredProduct$=this.route.queryParamMap.pipe(
             switchMap(params=>{
               this.category=params.get('category');
               return this.productService.getAll().pipe( 
                  switchMap(products=>{
                      const filteredProduct=!this.category?products:
                           products.filter(p => {
                              return p.category === this.category;
                            }) : 
                     return of(filteredProduct):
        
                  })
               )
             })
           ) 
        

        注意:我不检查代码,但这是我的想法,我希望这可以有用

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-09-24
          • 1970-01-01
          • 2021-03-07
          • 2020-11-25
          • 1970-01-01
          • 1970-01-01
          • 2021-10-02
          相关资源
          最近更新 更多