【问题标题】:Organize categories of products Angular组织产品类别 Angular
【发布时间】:2020-11-28 06:21:20
【问题描述】:

我正在尝试使此代码在 Angular 项目中工作,在 vanilla JS 中工作正常,但我在 Typescript 中的 for 循环遇到问题,现在在我的 Angular 视图中,我只打印带有 * 的产品列表ngFor 但我需要按类别分开。我希望用 map()filter() 等数组方法替换 for 循环,但我不知道该怎么做。如何使用 Angular *ngFor 实现这一点?

var products = [
        {id: 1, name: 'Apple', category: 'Fruit'},
        {id: 2, name: 'Orange', category: 'Fruit'},
        {id: 3, name: 'Blueberry', category: 'Jam'},
        {id: 4, name: 'Sugar', category: 'Sweet'},
        {id: 5, name: 'Candy', category: 'Sweet'},
        {id: 6, name: 'Cheese', category: 'Cheese'}
];

    
//get categories
let categories = [];
for (let i = 0; i < products.length; i++) {
    if(!categories.includes(products[i].category)){
        categories.push(products[i].category);
    }
}
console.log(categories);


//get products by category
for(item of categories){
    console.log(item);
    let filtered = products.filter(x => x.category == item);
    console.log(filtered);
}

/*
Expected output

Fruit
{id: 1, name: 'Apple', category: 'Fruit'},
{id: 2, name: 'Orange', category: 'Fruit'},

Jam
{id: 3, name: 'Blueberry', category: 'Jam'},

Sweet
{id: 4, name: 'Sugar', category: 'Sweet'},
{id: 5, name: 'Candy', category: 'Sweet'},

Cheese
{id: 6, name: 'Cheese', category: 'Cheese'}
*/

角度视图:

<div>
    <div *ngFor="let product of products">
         <div class="card-body">
             <p>{{product.name}}</p>
             <p>{{product.category}}</p>
        </div>
    </div>  
</div>

【问题讨论】:

  • 不完全是胡安,谢谢
  • “已过滤”不包含您需要的内容?
  • 在 vanilla JS 中工作正常,我在使用 typescript 时遇到了问题,我只是在寻找一种用数组方法而不是循环来组织它的方法。

标签: javascript angular typescript


【解决方案1】:

要显示您的数据,您可以将数据重新加工成更适合 ngFor 的形状。这是a repro on Stackblitz,这是代码:

ts:

import { Component, OnInit } from "@angular/core";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  name = "Angular";
  products = [
    { id: 1, name: "Apple", category: "Fruit" },
    { id: 2, name: "Orange", category: "Fruit" },
    { id: 3, name: "Blueberry", category: "Jam" },
    { id: 4, name: "Sugar", category: "Sweet" },
    { id: 5, name: "Candy", category: "Sweet" },
    { id: 6, name: "Cheese", category: "Cheese" }
  ];

  arrangedProducts = {};

  ngOnInit() {
    this.products.forEach(p => {
      if (!this.arrangedProducts || !this.arrangedProducts[p.category]) {
        this.arrangedProducts[p.category] = [p];
      } else {
        this.arrangedProducts[p.category].push(p);
      }
    });


    // if Object.values throw an error (Not working with ES2017 ?), use Object.keys().map() :
    // https://stackoverflow.com/a/42966443/9868549 and the next answer
    // this.arrangedProducts = Object.values(this.arrangedProducts);
    
    this.arrangedProducts = Object.keys(this.arrangedProducts).map(
      key => this.arrangedProducts[key]
    );
    console.log(this.arrangedProducts);
  }
}

html:

<div *ngFor="let arrayOfProducts of arrangedProducts; let i = index">
    <h2>{{arrayOfProducts[0].category}}</h2>
    <div *ngFor="let product of arrangedProducts[i]">
        {{product.name}}
    </div>
</div>

[编辑]:我为 Object.values 添加了一个更改,这会在 Stackblitz 中引发错误,以防它打扰您。


您也可以简单地对数据数组进行排序并显示为this other repro on Stackblitz,代码如下:

ts:

import { Component, OnInit } from "@angular/core";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent implements OnInit {
  name = "Angular";
  products = [
    { id: 1, name: "Apple", category: "Fruit" },
    { id: 6, name: "Cheese", category: "Cheese" },
    { id: 2, name: "Orange", category: "Fruit" },
    { id: 4, name: "Sugar", category: "Sweet" },
    { id: 3, name: "Blueberry", category: "Jam" },
    { id: 5, name: "Candy", category: "Sweet" },
  ];

  arrangedProducts = [];

  ngOnInit() {
    this.arrangedProducts = this.products.sort(this.compare);
    console.log(this.arrangedProducts)
  }

  compare(a, b) {
    if (a.category < b.category) {
      return -1;
    }
    if (a.category > b.category) {
      return 1;
    }
    return 0;
  }

  getPreviousCategory(i){
    if(i-1 < 0) return;
    return this.arrangedProducts[i-1].category;
  }
}

html:

<div *ngFor="let product of arrangedProducts; let i = index">
    <h2 *ngIf="getPreviousCategory(i) !== product.category">{{product.category}}</h2>
  {{product.name}}
</div>

第二种方法允许您根据需要直接对数组进行排序(adc 或 desc,取决于您在 compare 方法中放置的内容)。

【讨论】:

  • @sonEtLumiere 不客气 :) 如果这是您想要的答案,您可以将其标记为已接受的答案 ;)
【解决方案2】:

您可以在组件中派生出您的独特类别集,如下所示:

this.categories = [...new Set(this.products.map(item => item.category))];

(感谢@Vlad Bezden https://stackoverflow.com/a/35092559/442665

然后您的视图将根据类别有条件地显示它们:

<div *ngIf="product.category === category">

这是一个例子:

import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  products = [
    {id: 1, name: 'Apple', category: 'Fruit'},
    {id: 2, name: 'Orange', category: 'Fruit'},
    {id: 3, name: 'Blueberry', category: 'Jam'},
    {id: 4, name: 'Sugar', category: 'Sweet'},
    {id: 5, name: 'Candy', category: 'Sweet'},
    {id: 6, name: 'Cheese', category: 'Cheese'}
  ];
  categories;

  constructor() {
    this.categories = [...new Set(this.products.map(item => item.category))];
    console.log(this.categories);
  }
}

这是视图:

<div>
  <div *ngFor="let category of categories; index as i;">
    <div class="header">{{category}}</div>
    <div *ngFor="let product of products; index as i;">
      <div *ngIf="product.category === category">
      {{product.name}}
      </div>
    </div>
  </div>
</div>

CSS:

.header {
  font-weight: bold;
  margin-bottom: 10px;
  margin-top: 20px;
  text-decoration: underline;
}

以下是示例: https://codesandbox.io/s/bold-kalam-du9n7?fontsize=14&hidenavigation=1&theme=dark

【讨论】:

    【解决方案3】:

    我以如下方式在我的 Angular 应用中解决了此类问题:

    CategoryProductsComponent.ts文件中,

      @Input() products: IProduct[];
      categorizedProducts = {};
    
      constructor(private router: Router, private cartService: CartService) {}
    
      ngOnInit(): void {
        this.products.forEach((p) => {
          if (!this.categorizedProducts || !this.categorizedProducts[p.category]) {
            this.categorizedProducts[p.category] = [p];
          } else {
            this.categorizedProducts[p.category].push(p);
          }
        });
    
        this.categorizedProducts = Object.keys(this.categorizedProducts).map(
          (key) => this.categorizedProducts[key]
        );
        console.log(this.categorizedProducts);
      }
    

    CategoryProdcutsComponent.html文件中,

        <!-- container -->
            <div class="container">
              <!-- row -->
              <div class="row" *ngFor="let arrayOfProducts of categorizedProducts; let i = index">
        
        
                <!-- section title -->
                <div class="col-md-12">
                  <div class="section-title">
                    <h2 class="title category-title"> {{arrayOfProducts[0].category}} </h2>
                  </div>
                </div>
                <!-- /section title -->
          
                <!-- Products tab & slick -->
                <div class="col-md-12">
                  <div class="row">
                    <div class="card-deck">
                      <div class="col-md-4 col-sm-6" *ngFor="let product of categorizedProducts[i]">
                        <div class="card my-2">
                          <img
                            [src]="product.image"
                            alt="{{ product.title }}"
                            width="200px"
                            height="300px"
                            class="card-img-top"
                            style="cursor: pointer"
                            (click)="selectProduct(product._id)"
                          />
                          <div class="card-header">
                            <div class="card-title">
                              <p>{{ product.title.substr(0, 50) | uppercase }}</p>
                            </div>
                          </div>
                          <div class="card-body">
                            <h6>{{ product.description.substr(0, 150) }} ...</h6>
                            <h3 class="">{{ product.price | currency: "USD" }}</h3>
                            <p>
                              <del class="product-old-price">{{
                                product.price + product.price * 0.1 | currency: "USD"
                              }}</del>
                              (10% Off)
                            </p>
                          </div>
          
                          <div
                            class="row d-flex justify-content-center border-primary my-3"
                          >
                            <div class="col-md-6">
                              <button
                                class="btn btn-outline-primary btn-sm btn-block"
                                [class.disabled]="product.quantity < 1"
                                [class.btn-outline-danger]="product.quantity < 1"
                                (click)="
                                  product?.quantity <= 0
                                    ? notifyEmpty(product?.title)
                                    : addToCart(product?._id)
                                "
                              >
                                {{ product.quantity < 1 ? "NO STOCK" : "Add To Cart" }}
                              </button>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
                <!-- Products tab & slick -->
              </div>
             <!-- /row -->
          </div>
      <!-- /container -->
    

    【讨论】:

      猜你喜欢
      • 2012-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多