Как найти элементы массива по индексу из другого массива и вывести обновлённый список во Vue

112
14 декабря 2020, 02:10

Делаю фильтр по нажатию на кнопку должно найти у item категорию которая совпадает с категорией на кнопку, эти элементы оставить а остальные скрыть. Столкнулся с проблемой что в методе setSocialSortBy я сделал массив который содержит Index элементов у которых есть эта категория matchArr = [1,3,5 ...], но не получаеться теперь отфильтровать this.items по этому новому массиву matchArr. Как это можно сделать?

json который приходит с api:
    {name: 'title 1', category: 'cat 1'},
    {name: 'title 2', category: 'cat 2'},
    {name: 'title 3', category: 'cat 1'},
    {name: 'title 4', category: 'cat 2'} ...
 <button v-for="cat in cats" @click="setCatSortBy(cat)">{{cat}}</button>
    <div v-if="items.length > 0">
      <div v-for="item in items">{{item.name}}</div>
    </div>
    <script>
    export default {
    data() {
       items: [],
       cats: []
    },
    created () {
                this.fetchItems();
            },
    methods: {
    fetchItems() {
                    this.loading = true;
                    fetch("/api/items")
                        .then(res => res.json())
                        .then(res => {
                            this.items = res;
                            let catArr = [];
                            this.items.forEach((item) => {
                                catArr.push(item.category);
                            });
                            catArr.filter((value, index, arr) => {
                                if (arr.indexOf(value) === index) {
                                    this.cats.push(value.toLowerCase());
                                }
                            });
                        });
                },
               setCatSortBy(name) {
                    let matchArr = [];
                    this.items.filter((value, index) => {
                        if (value.category.toLowerCase() === name.toLowerCase()) {
                            matchArr.push(index);
                        }
                    });
                }
    }
    }
    </script>
Answer 1

Думаю, что стоит повторно обратиться к методам фильтрации, которые описаны в этом ответе.

Метод filter() не изменяет массив к которому применяется, он возвращает новый массив. Т.е. нужно сделать так:

this.items = this.items.filter(...)

Но если вы так сделаете, то из оригинального массива будут удалены отфильтрованные записи. И при дальнейшей фильтрации, этот массив будет "худать", пока не станет пустым.

Именно поэтому вводится промежуточный массив filteredItems для фильтрации, чтобы оригинальный оставался не тронутым.

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

new Vue({ 
  el: '#app', 
 
  data: { 
    // Модель с записями. 
    items: [], 
    // Модель с категориями. 
    categories: [], 
    ready: false, 
    search: { 
      category: '', 
    } 
  }, 
 
  computed: { 
    // Вычисляемый список зависит от выбранной категории. 
    // При изменении категории, список будет отфильтрован. 
    // Метод filter() создаёт новый массив со всеми элементами, 
    // прошедшими проверку. 
    // https://ru.vuejs.org/v2/guide/list.html#Замены-в-массиве 
    // https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Возвращаемое_значение 
    filteredItems() { 
      let category = this.search.category 
 
      return category 
        ? this.items.filter(item => item.category === category) 
        : this.items 
    } 
  }, 
 
  /** 
   * Используем хук `mounted` для получения записей. 
   */ 
  async mounted() { 
    const response = await this.fetchArticles() 
 
    this.items = response.data 
 
    this.categories = this.makeCategoryList(this.items) 
  }, 
 
  methods: { 
    // Составляем список всех категорий. 
    // Нам нужны только уникальные значения, поэтому 
    // воспользуемся созданием массива ч/з Set. 
    // За одно и отсортируем. 
    makeCategoryList(items) { 
      let cats = new Set() 
 
      items.map(item => cats.add(item.category)) 
 
      return [...cats].sort((a, b) => a.localeCompare(b)) 
    }, 
 
    fetchArticles() { 
      this.ready = false 
 
      // Импровизация получения данных ч/з ajax. 
      return new Promise(resolve => { 
        setTimeout(() => { 
          this.ready = true 
 
          resolve({ 
            // Сортировка: id asc. 
            data: [{ 
              id: 4, 
              name: 'Voluptatem enim optio', 
              category: 'cat 3' 
            }, { 
              id: 8, 
              name: 'Eum praesentium autem', 
              category: 'cat 2' 
            }, { 
              id: 12, 
              name: 'Voluptatem nihil voluptate', 
              category: 'cat 1' 
            }, { 
              id: 18, 
              name: 'Debitis illum ex eum', 
              category: 'cat 3' 
            }], 
            meta: {} 
          }) 
        }, 2000) 
      }) 
    } 
  }, 
})
.form__group { 
  margin-bottom: 1rem; 
} 
 
.form__control { 
  display: inline-block; 
  padding: .375rem .75rem; 
  line-height: 1; 
  color: #495057; 
  background-color: #fff; 
  background-clip: padding-box; 
  border: 1px solid #ced4da; 
  transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out; 
} 
 
.form__control:focus { 
  color: #495057; 
  background-color: #fff; 
  border-color: #80bdff; 
  outline: 0; 
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, .25); 
} 
 
.alert { 
  padding: 0.75rem 1.25rem; 
  margin-bottom: 1rem; 
  border: 1px solid transparent; 
} 
 
.alert-info { 
  color: #2f6473; 
  background-color: #def2f8; 
  border-color: #d1edf6; 
}
<div id="app"> 
  <div class="filter__box"> 
    <div class="form__group"> 
      <label for="">Фильтровать по категории</label> 
      <select v-model="search.category" class="form__control"> 
        <option value="">- Категория -</option> 
        <option v-for="(category, index) in categories" :value="category">{{ category }}</option> 
      </select> 
      <!-- 
                Используем вычисляемое свойство, необходимость в кнопке отпадает. 
            --> 
    </div> 
  </div> 
 
  <div v-if="!ready" class="alert alert-info">Загрузка записей, ожидайте 2 сек ...</div> 
 
  <div v-if="ready && Boolean(filteredItems.length)" class="items"> 
    <template v-for="(item, index) in filteredItems" :key="item.id"> 
            <article class="article"> 
                <h3 class="article__title">#{{ item.id }} {{ item.name }}</h3> 
            </article> 
        </template> 
  </div> 
 
  <div v-if="ready && !Boolean(filteredItems.length)" class="alert alert-info">Нет информации для отображения.</div> 
</div> 
 
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script>

READ ALSO
Передача значение input на другую страничку

Передача значение input на другую страничку

У меня есть две странички takenamehtml и givename

87
пользовательский статус на сайте nodejs

пользовательский статус на сайте nodejs

задача состоит в том чтоб, создать кнопку onlineточнее когда любой пользователь/гость на сайте смотри любой пост, нужно чтоб статус автора был...

94
Не работает js на моб устройствах

Не работает js на моб устройствах

В браузерах на андроидах не работает выпадающие меню на сайтеJS код:

94
Удаление данных с таблицы React/Redux

Удаление данных с таблицы React/Redux

Пытаюсь удалить данные с таблицы, и никак не пойму что делаю не такНа сервере все нормально удаляется, а на клиенте обновленную табличку увижу...

132