Angular5 - 过滤对象数组

时间:2018-01-11 15:22:03

标签: javascript angular typescript filter

我正在尝试过滤产品视图,但我不知道为什么原始数组被修改,导致过滤不正确...

categories 是一个包含类别{title,products []}

的对象的数组

categoriesView 我希望它是一个过滤后的数组

filterByKeyword(keyword: string) {
    let k = keyword.toLowerCase();

    this.categoriesView = this.categories.filter((c) => {
      for(let q = 0; q < c.products.length; q++) {
        return c.products[q].title.toLowerCase().indexOf(k) >= 0;
      }
    });

    // filter products of each category:
    for(let q = 0; q < this.categoriesView.length; q++) {
      for(let z = 0; z < this.categories.length; z++) {
        if(this.categoriesView[q].title == this.categories[z].title){
          this.categoriesView[q].products = this.categories[z].products.filter((p) => {
              return p.title.toLowerCase().indexOf(k) >= 0;
          });
        }
      }
    }

    console.log("Categories View: ", this.categoriesView);
    console.log("Categories: ", this.categories);
}

第一个带有类别的过滤器可以正常工作当我深入研究产品时会出现问题并修改原始数组。

4 个答案:

答案 0 :(得分:2)

很抱歉,但我必须介入。

您的过滤和代码非常糟糕。

在这里,它被重写,更清晰,更简单,甚至可能起作用:

filterByKeyword(keyword: string) {

    const k = keyword.toLowerCase();

    this.categoriesView = this.categories.filter(c => {
      let ret = false;
      for(let q of c.products) {
        if(q.title.toLowerCase().includes(k)) { ret = true; }
      }
      return ret;
    });

    // Even cleaner
    // this.categoriesView = this.categories.filter(c => c.products.find(p => p.title.toLowerCase().includes(k)));

    for (const view of this.categoriesView) {
      for (const cat of this.categories) {
        if (view.title === cat.title) {
          view.products = cat.products.filter(p => p.title.toLowerCase().includes(k));
        }
      }
    }

    console.log("Categories View: ", this.categoriesView);
    console.log("Categories: ", this.categories);
}

答案 1 :(得分:1)

存在以下问题:

this.categories.filter( (c) => {...} )

您的数组在第一轮返回时未正​​确迭代。您应该使用临时布尔值作为循环的缓冲区,然后返回它。

此外,concider使用Array.prototype.mapArray.prototype.reduce重构您的代码,它将使您的代码更具可读性

this.categoriesView = this.categories.filter(c => {
    return c.products.reduce( (acc, product) => {
        return acc || product.title.toLowerCase().includes(k);
    }, false);
});

答案 2 :(得分:1)

应该有效:

filterByKeyword(keyword: string) {
    const k = keyword.toLowerCase();
    this.categoriesView = this.categories.map(x => Object.assign({}, x));
    this.categoriesView = this.categoriesView.filter((category) => {
        category.products = category.products.filter(
          (product)=> product.title.toLowerCase().includes(k));

        return category.products.length>0 }
      );
    if(this.categoriesView.length===0){
      this.categoriesView = this.categories.map(x => Object.assign({}, x));
    }
  }

答案 3 :(得分:0)

在javascript中,对象通过引用传递。所以 categoriesView实际上是对categories数组的引用,在一个数组中更改属性将同时更改这两个属性。 如果要创建单独的对象,可以使用angular.copy()

this.categoriesView = angular.copy(this.categories.filter((c) => {
  for(let q = 0; q < c.products.length; q++) {
    return c.products[q].title.toLowerCase().indexOf(k) >= 0;
  }
}););

查看更多信息here