Javascript filter массив объектов пропускает пустую строку - PullRequest
2 голосов
/ 04 июня 2019

Я создаю REST API в NodeJS. Я строю нумерацию, сортировку и фильтрацию на стороне сервера.

У меня есть простая реализация метода фильтра. Это работает, если элемент не содержит пустых строк. Однако, если элемент содержит пустую строку, метод .toString() завершается ошибкой, поскольку item[filterBy] равен null.

Невозможно прочитать свойство 'toString' с нулевым значением

Как я могу обновить функцию фильтра, чтобы просто возвращать true, если элемент содержит пустую строку, чтобы пропустить операции сравнения?

  // Apply filter to array of objects
  // TODO: Empty strings breaks the filter
  items = items.filter(item =>
    item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1)

Ответы [ 5 ]

2 голосов
/ 04 июня 2019

Возможно что-то вроде этого:

const filterValue = 'abc'
const filterBy = 'name'
const items = [
  {x: 1, name: 'abc'},
  {x: 2, name: 'def'},
  {x: 3, noname: 'def'},
  {x: 4, name: 'ABCDEF'},
]

const newItems = items.filter(item =>
    !(filterBy in item) || item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1)
    
console.log(newItems)

Все, что мы здесь делаем, это проверяем, есть ли у item свойство filterBy.

Мне не совсем понятно, в чем проблема с пустыми строками. Скорее всего, вы получите эту ошибку, если item[filterBy] не определено. Вот что мы здесь проверяем.

Если вместо этого вы хотите пропустить те, у которых нет соответствующего свойства, переключитесь с !(filterBy in item) || ... на (filterBy in item) && ....

2 голосов
/ 04 июня 2019

Чтобы пропустить элемент, содержащий пустую строку, попробуйте это:

item[filterBy] && item[filterBy].toString()

Итак, ваш код будет:

items = items.filter(item =>
item[filterBy] && item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1)
1 голос
/ 04 июня 2019

flatMap() - это .map() и .flat() вместе взятые.Он может действовать как обратный .filter(), напрямую возвращая или не возвращая значения.Подробности смотрите в демоверсии.

const items = [{
  id: 'a',
  pn: 'B',
  desc: ''
}, {
  id: 'b',
  pn: 'c',
  desc: 'd'
}, {
  id: 'c',
  pn: 'k',
  desc: null
}, {
  id: 'i',
  pn: 'k',
  desc: 2
},, {
  id: 'o',
  pn: 'x',
  desc: 3
}];

// Utility function that returns a 'friendlier' value
function clean(obj) {
  return obj == null ? false : Array.isArray(obj) ? obj : obj.constructor.name.toLowerCase() === "object" ? obj.toString().trim().toLowerCase() : typeof obj === "string" ? obj.toString().trim().toLowerCase() : Number(parseFloat(obj)) === obj ? obj : false;
}

// Filters by a single key and multiple values
let filterKey = clean('desc');
let filterVal = clean(['d', 2, 'f']);

/* It returns each value in a sub-array an empty array will remove
the value. In the final stage it flattens the array of arrays into a normal array
*/
let list = items.flatMap(item => {
  return Object.entries(item).flatMap(([key, value]) => filterKey === (clean(key)) && [...filterVal].includes(clean(value)) ? [clean(value)] :[]);
});

console.log(list);
1 голос
/ 04 июня 2019

Может быть:

items = items.filter(
    item => item[filterBy] && item[filterBy].toString ?
        item[filterBy].toString().trim().toLowerCase().indexOf(filterValue.toLowerCase()) !== -1 :
        false
)
0 голосов
/ 04 июня 2019

Цепные фильтры корректны и не влияют на производительность.

const filterValue = 'John'
const filterBy = 'name'
const items = [
  {id: 1, name: 'John'},
  {id: 2, name: 'Doe, John'},
  {id: 3, ref: 1},
  {id: 4, name: 'No one'},
  {id: 5, name: null}
]

let fItems = items.filter(item => item[filterBy])
                  .filter(item => item[filterBy].toString().trim().toLowerCase()
                     .indexOf(filterValue.toLowerCase()) !== -1)
   
console.log(fItems);

Обновление: исправил код.

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