Filter array and match at least one condition

Viewed 955

I'd like to solve the following problem: I would like to filter an array by certain conditions with Vue.js and lodash (or pure JavaScript).

My objects

  • I got a list of Items. Each item contains (optional) categories.
  • The object Car can have a category.

Array of Objects Items

"data": [
    {
      "id": 1,
      "title": "Item 1",
      "categories": [
        {
          "id": 4,
          "title": "category 4",
          "description": "",
        },
        {
          "id": 5,
          "title": "category 5",
          "description": "",
        }
      ]
    },
    {
      "id": 2,
      "title": "Item 2",
      "categories": []
    },
    {
      "id": 3,
      "title": "Item 3",
      "categories": []
    }
  ]

Object Car

{
  "category": {
    "id": 5,
    "title": "category 5",
    "description": ""
  },
  "title": "Test"
}

My goal

I would like to only show those Items, which are passing at least one of these rules:

  • The Item has at least one category that matches the category of the Car
  • The Item has no category set

My approach

I am using a computed value to filter this.items:

computed: {
        filteredItems: function () {
            let vm = this;
            return _.filter (this.items, function (item) {
                return _.includes (item.categories, vm.car.category );
            });
        }
    },

Current result:

filteredItems is always empty.

2 Answers

You need to do one more level of checking on categories because you need to test against each item inside it. With regular javascript you can do that with some() which will return true if any of the items match.

let data = [{"id": 1,"title": "Item 1","categories": [{"id": 4,"title": "category 4","description": "",},{"id": 5,"title": "category 5","description": "",}]},{"id": 2,"title": "Item 2","categories": []},{"id": 3,"title": "Item 3","categories": []}]
let  car = {"category": {"id": 5,"title": "category 5","description": ""},"title": "Test"}

let filtered = data.filter(item => !item.categories || item.categories.length === 0 ||  item.categories.some(cat=> cat.id === car.category.id))
console.log(filtered)

With lodash you'd need something like

result = _.filter(data, ({categories}) =>
    _.isEmpty(categories) ||
    _.some(categories, cat => cat.id === car.category.id))

If you'd like to compare the whole category objects, not just ids, then

_.filter(data, ({categories}) => 
    _.isEmpty(categories) || 
    _.some(categories, cat => _.isEqual(cat, car.category)
    ))
Related