Фильтровать массив с несколькими условиями и некоторые из них могут быть нулевыми - PullRequest
0 голосов
/ 24 января 2020

У меня есть файл JS, который используется для визуализации v-списка vuetify, который может иметь 2 уровня (узлы с дочерними элементами, и они являются необязательными).

Мне нужно добавить фильтр из В поле поиска, в которое входит пользователь, я мог бы отфильтровать первый уровень, но у меня проблемы со вторым, потому что иногда они имеют свойство "children" в null, а в других случаях они имеют значения. Меню выглядит так:

const Menu = [
    {
        heading: null,
        icon: "mdi-security",
        text: "Login",
        url: {
            name: "login"
        },
        exactUrl: false,
        children: null,
        meta: {
            publicPath: true
        }
    },
    {
        heading: null,
        icon: "search",
        text: "Lista de Funcionarios",
        url: {
            name: "home"
        },
        exactUrl: true,
        children: null,
        meta: {
            publicPath: true
        }
    },
    {
        heading: {
            text: "Mantenimientos",
            publicPath: false
        },
        icon: null,
        text: "",
        url: null,
        exactUrl: null,
        children: null,
        meta: null
    },
    {
        heading: null,
        icon: "mdi-account-group",
        text: "Departamentos",
        url: {
            name: "departamentos"
        },
        exactUrl: false,
        children: null,
        meta: {
            publicPath: false
        }
    },
    {
        heading: null,
        icon: "mdi-account-circle",
        text: "Funcionarios",
        url: {
            name: "funcionarios"
        },
        exactUrl: false,
        children: null,
        meta: {
            publicPath: false
        }
    },
    {
        heading: null,
        icon: "settings",
        text: "Operación",
        url: null,
        exactUrl: false,
        children: [{
            icon: "add",
            text: "Cargar Pedidos",
            url: {
                name: "departamentos"
            }
        },
        {
            icon: "playlist_add_check",
            text: "Aprobar Pedidos",
            url: {
                name: "areas"
            }

        },
        {
            icon: "content_copy",
            text: "Remitir Pedidos",
            url: {
                name: "maps"
            }
        }
        ],
        meta: null
    },
];

export default Menu;

И моя вычисленная функция такова:

filteredMenu() {
  return this.menus.filter(menu =>
    menu.text.toLowerCase().includes(this.search.toLowerCase())
  );
}

Как я могу фильтровать одновременно на обоих уровнях?

РЕДАКТИРОВАТЬ 1 : "

Ожидаемый результат:

enter image description here

Ответы [ 5 ]

1 голос
/ 25 января 2020

Я думаю, вы ищете что-то вроде этого, которое, конечно, использует рекурсию. Важно то, как он использует рекурсию. Это означает, что вы хотите проверить дочерние элементы сначала , а затем определить, есть ли дочерние элементы (сохраняет родительский), или , если текущий пункт меню имеет данный текст, он соответствует. Вы захотите родителя для всех подходящих потомков, пройдя весь путь внутрь для каждого ветвления структуры вашего меню, а затем вернетесь к элементам root -уровня.

Это вызовет зондирование на потомки, которые затем выполняют всю процедуру дальше внутрь, пока не останется потомков, возвращая каждый входящий набор с совпадениями (и связанным с ним родительским элементом), а затем резервное копирование для работы на следующем более высоком уровне. Думайте об этом как о следующей диаграмме:

1 match
2 match
        3az < match
        3ay < match
        3ax < match
    3a < [...match] match
    3b < match
3 [...match] match
    4a < match
4 [...match] match
5 match

Кроме того, вы не хотите фильтровать, вы хотите уменьшить до набора .

const search = (items, text) => {
  const hasText = item => item.text.toLowerCase().includes(text.toLowerCase())
  const probe = (found, item) => {
    item.children = (item.children || []).reduce(probe, [])

    if (item.children.length || hasText(item)) {
      found.push(item)
    }

    return found
  }

  return items.reduce(probe, [])
}

... elsewhere ...

return search(this.menus, 'c')

https://jsfiddle.net/81wkh5df/6/

Возвращает:

  • Список функций ios
  • Функции ios
  • Операция
    • Cargar Pedidos
1 голос
/ 24 января 2020

вы можете использовать полезную функцию _isExist ()

const _isExist = (menu, value) => menu.text.toLowerCase().includes(value.toLowerCase())

, и вы можете использовать ее для поиска внутри массива дочерних элементов, если он существует

filteredMenu() {
  return this.menus.filter(
    menu =>
        _isExist(menu, this.search) ||
        (menu.children && menu.children.some(childMenu => _isExist(childMenu, this.search))),
  )
}
1 голос
/ 24 января 2020

Создайте функцию, которую вы можете вызывать рекурсивно.

methods: {
  filterMenuItems(menuItems) {
    return menuItems.filter(menuItem => {
      let found = menuItem.text.toLowerCase().includes(this.search.toLowerCase());
      if (!found && Array.isArray(menuItem.children)) {
        found = this.filterMenuItems(menuItem.children);
      }
      return found;
    });
  }
}

Теперь ваше вычисленное свойство может возвращать this.filterMenuItems(this.menus)

filteredMenu() {
    return this.filterMenuItems(this.menus);
}

Это также допускает бесконечные подуровни

1 голос
/ 24 января 2020

вы можете использовать Разрушающее присваивание , чтобы получить значение и установить предопределенное значение, затем, используя Some , вы можете проверить условие truthy для Array.

другими словами, вам нужно сделать следующее:


filteredMenu() {
  return this.menus.filter(menu => {
    // check if the parent has the value
    const parentIncludesText = menu.text.toLowerCase().includes(this.search.toLowerCase())

    // define a predefined value in case 'children' is null
    const { children = [] } = menu || {}

    // check if some of the childs has the value.
    const childrenIncludesText = children.some(child => child.text.toLowerCase().includes(this.search.toLowerCase()))

    // then return the result of the parent and the children.
    return parentIncludesText || childrenIncludesText
  });
}
0 голосов
/ 24 января 2020

Если я прав, вы хотите проверить, не равны ли его дочерние элементы тоже? Вы можете использовать &&

filteredMenu() {
  return this.menus.filter(menu =>
    menu.children && menu.text.toLowerCase().includes(this.search.toLowerCase())
  );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...