Как отфильтровать массив на основе значений большого дочернего массива? - PullRequest
3 голосов
/ 23 сентября 2019

Я пытаюсь отфильтровать родительский массив на основе значений большого дочернего массива, но мой подход к фильтрации не работает должным образом, и пользовательский интерфейс не обновляется.

Вот моя функция фильтрации.

filterIt($event) {
    this.filter.RegCategoryName = $event.target.value;
    this.dataObject = staticData.filter(value => 
        value.List.filter(ch => ch.RegistrationCategory.filter(gChild =>
            Object.keys(this.filter).every(ob => 
                String(gChild[ob]).toLowerCase().includes(String(this.filter[ob]).toLowerCase())
            )
        )).length
    )
}

Демонстрация в реальном времени

Ожидание:

Когда пользователь вводит new Course, он должен отображать только DP Programmeв столбце Программы.

1 Ответ

2 голосов
/ 23 сентября 2019

Этого можно достичь, используя комбинацию методов map, filter и some Array.Используйте оператор распространения ..., чтобы исходный массив не обновлялся в дочерних объектах.

filterIt($event) {
    this.filter.RegCategoryName = $event.target.value;
    this.dataObject = staticData.filter(value => {
        const data = { ...value };
        data.List = data.List.map(ch => {
            const list = { ...ch };
            list.RegistrationCategory = list.RegistrationCategory.filter(gChild => {
                return gChild.RegCategoryName.toLowerCase().indexOf(this.filter.RegCategoryName.toLowerCase()) !== -1
            });
            return list;
        });
        return data.List.some(list => !!list.RegistrationCategory.length);
    });
}

Примечание : избегайте использования имен переменных с заглавной буквой.

Вот рабочий пример для StackBlitz .

Объяснение :

Структура, используемая здесь, довольно сложна, поэтому я полагаю, что я 'начну изнутри.Давайте начнем с самого внутреннего filter.

list.RegistrationCategory = list.RegistrationCategory.filter(gChild => {
    return gChild.RegCategoryName.toLowerCase().indexOf(this.filter.RegCategoryName.toLowerCase()) !== -1
});

Метод filter() создает новый массив со всеми элементами, которые проходят тест, реализованный предоставленной функцией.

Это должно быть достаточно ясно.Здесь используется то же условие, что и в фильтре Angular Material mat-table.Это отфильтрует, если RegCategoryName содержит критерий поиска.Я говорю содержать, потому что это будет соответствовать new Course, даже если ваш поисковый термин ew.Если это не то, что вы хотите, вы можете использовать startsWith вместо этого.Это будет соответствовать, только если ваш поисковый термин new, а не ew.

list.RegistrationCategory = list.RegistrationCategory.filter(gChild => {
    return gChild.RegCategoryName.toLowerCase().startsWith(this.filter.RegCategoryName.toLowerCase())
});

Переход к первому родительскому массиву List.Мы не хотим filter или изменять объекты здесь.Вместо этого мы просто хотим тот же объект, но с новым фильтрованным RegistrationCategory.Это хорошо подходит для map, так как map возвращает массив с таким же количеством объектов (с некоторыми изменениями элементов в объекте, если это необходимо).

map() метод создает новый массив с результатами вызова предоставленной функции для каждого элемента в вызывающем массиве.

Так что в нашем map мы будем обновлять RegistrationCategory используя filter, который мы создали выше.Мы не можем изменить ch напрямую, поскольку это приведет к изменению исходного объекта.Таким образом, вместо этого мы будем мелко клонировать ch, используя синтаксис распространения , в переменную list, модифицировать RegistrationCategory в нашей новой переменной list, используя приведенный выше filter, и возвращать объект.Теперь это дает нам массив List как есть, просто обновляя RegistrationCategory в каждом объекте.

Теперь для финальной части нам нужно от filter до staticData.Как и в map, мы снова будем использовать синтаксис распространения, так как мы не хотим обновлять исходный объект.data.List теперь будет фильтровать каждый RegistrationCategory благодаря нашему внутреннему фильтру, поэтому нам просто нужно вернуть значение true / false в зависимости от того, есть ли в массиве List какой-либо объект, длина которого RegistrationCategory большечем 0. Мы можем использовать some для этого.

Метод some() проверяет, прошел ли хотя бы один элемент в массиве тест, реализованный предоставленной функцией.Он возвращает логическое значение.

Так что если любой RegistrationCategory в массиве List имеет длину больше 0 (так как это все, что нас интересует, присутствует ли какой-либо RegistrationCategory после нашегосамый внутренний фильтр отфильтровал List), он возвращает true и добавляется к отфильтрованному dataObject.

Таким образом, мы получаем каждый объект в staticData, чей массив List содержит объект, где RegistrationCategory имеет некоторые данные.

Надеюсь, это прояснит, почему у вас возникли проблемы с вашим кодом и почему вы не можете использовать фильтр для всех трех массивов.

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