Angular 5 - несколько фильтров не работают в массиве объектов - PullRequest
0 голосов
/ 01 сентября 2018

У меня есть угловой компонент, который имеет 3 фильтра (категория, рейтинг и цена), и при выборе этих фильтров я должен показывать только соответствующие данные, поэтому я создал трубу и передал все три выбранных значения. На самом деле мой фильтр категорий работает полностью нормально, но два других фильтра (рейтинг и цена) не работают должным образом.

Данные Json:

"allBusiness": [    
        {
            "category": "XYZ",
            "description": "something something",
            "business": [
             {
                "type": "Store",
                "rating": 4,
                "price" : "$"
             },
             {
                "type": "Store",
                "rating": 3,
                "price" : "$"
             },
             {
                "type": "Store",
                "rating": 5,
                "price" : "$$"
             }           
             ]

        },
        {
            "category": "ABC",
            "description": "Testing",
            "business": [
             {
                "type": "Online",
                "rating": 3,
                "price" : "$"
             },
             {
                "type": "Store",
                "rating": 2,
                "price" : "$"
             },
             {
                "type": "Store",
                "rating": 1,
                "price" : "$$"
             }           
             ]

        }
]

FilterPipe.ts:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'filter'
})
export class FilterPipe implements PipeTransform {

  transform(allBusiness: any[], selectedCategory: string, selectedRating: number, selectedPrice: string): any {
    if (allBusiness && allBusiness.length){
        return allBusiness.filter(item =>{
            if (category && item.category.indexOf(selectedCategory) === -1){
                return false;
            }
            if (rate && item.business.filter(rt => rt.rating != selectedRating)){ //tried filter, findIndex, some but nothing works
                return false;
            }
            if (price && item.business.find(pr => pr.price != selectedPrice)){ //same here nothing is working
                return false;
            }
            return true;
       })
    }
    else{
        return items;
    }
  }
}

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 01 сентября 2018

У нас есть 2 фильтра: для внешнего и внутреннего списка, позвольте мне разделить его на allBusinessFilterBy: {category?: string} и businessFilterBy: {rating?: number; price?: string;}.

interface BusinessFilterBy {
  rating?: number;
  price?: string;
}

interface AllBusinessFilterBy {
  category?: string;
}


function isNill(item) {
  return item === undefined || item === null || (item !== item);
}

function isBusiness(item, filterBy: BusinessFilterBy) {
  return (isNill(filterBy.rating) || item.rating === filterBy.rating) && (isNill(filterBy.price) || item.price === filterBy.price);
}

function isAllBusiness(item, filterBy: AllBusinessFilterBy) {
  return isNill(filterBy.category) || item.category === filterBy.category;
}

function filterBusiness(item, businessFilterBy: BusinessFilterBy) {
  return [{
    ...item,
    business: item.business.filter(businessItem => isBusiness(businessItem, businessFilterBy))
  }];
}

function transform(allBusiness = [], allBusinessFilterBy: AllBusinessFilterBy = {}, businessFilterBy: BusinessFilterBy = {}) {
  if (!allBusiness && !allBusiness.length) {
    return allBusiness;
  }
  return allBusiness.reduce((acc, item) => [...acc, ...isAllBusiness(item, allBusinessFilterBy) ? filterBusiness(item, businessFilterBy) : []], []);
}
0 голосов
/ 01 сентября 2018

Я немного не уверен, что вы имеете в виду, когда говорите Я должен показывать только соответствующие данные в отношении фильтрации по rating или price. Я полагаю, вы хотите:

  • Отфильтровать / исключить элемент в allBusiness, если ни одна из записей в его массиве business не содержит указанные rating и price.
  • Вывести / включить элемент, если он содержит, по крайней мере, одну запись в массиве business с указанными rating и price.

Если это так, вы можете сделать это:

return allBusiness.filter(item => 
   (selectedCategory && item.category && item.category.indexOf(selectedCategory) > -1)
   && (selectedRating && item.business && item.business.length > 0 && item.business.find(rt => rt.rating == selectedRating))
   && (selectedPrice && item.business && item.business.length > 0 && item.business.find(pr => pr.price == selectedPrice)))

Теперь, если вы хотите отфильтровать allBusiness так, чтобы вы хотели только запись, в которой все элементы в его массиве business имеют указанные rating и price, вы можете сделать это:

return allBusiness.filter(item => 
   (selectedCategory && item.category && item.category.indexOf(selectedCategory) > -1)
   && (selectedRating && item.business && item.business.length > 0 && !item.business.find(rt => rt.rating != selectedRating))
   && (selectedPrice && item.business && item.business.length > 0 && !item.business.find(pr => pr.price != selectedPrice)))

Примечание:

find() получает первый элемент в массиве, который соответствует заданному вами условию. Если никакие элементы не соответствуют условию, возвращается undefined.

filter(), с другой стороны, дает вам новый массив, содержащий только те элементы из оригинала, которые соответствуют заданному вами условию. Если ни одно из элементов не соответствует условию, оно дает пустой массив.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...