Написать фильтр для checkbox во Vue.js

81
20 декабря 2020, 19:20

Нужно выводить данные по определенным требованиям - по полу.

<v-radio label="Both" name="gender" value=""></v-radio>
<v-radio label="Male" name="gender" value="Male" ></v-radio>
<v-radio label="Female"  name="gender" value="Female"></v-radio>

Данные о людях хранятся в store(vuex) -

guides:   [
      { id: 1,popularGuide: true, name: 'Karina',  rate: '41',gender: 'female', photo: require('./assets/img/person1.jpg')},  
      { id: 2,popularGuide: true,name: 'Nicolas', rate: '32', gender: 'male',photo: require('./assets/img/person2.jpg') },

При нажатии на определенный checkbox вывести весь список, или только женщин, или только мужчин.

Сюда выводятся данные:

<v-flex xs4 sm4 md4 lg4 v-for="guide in guides" :key="guide.name"> и так далее.

Я пробовала и filters и через getters и через библиотеку fuse.js.

Пример из одной моей попытки:

   if ( '' !== gender ) {
      // 
      guides= guides.filter( function ( guide) {
        return guide.gender === gender;
      } );
    }

Подскажите, через что лучше сделать выборку и как это сделать?

Answer 1

Вот один из вариантов для решения вашей задачи:

<!DOCTYPE html> 
<html dir="ltr" lang="ru"> 
 
<head> 
  <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet"> 
  <link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet"> 
  <link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet"> 
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"> 
</head> 
 
<body> 
  <div id="app"> 
    <v-app> 
      <v-content> 
        <v-container> 
 
          <v-radio-group v-model="filterGender" @change="sortGuide"> 
            <v-radio label="both" key="both" value="both"></v-radio> 
            <v-radio label="male" key="male" value="male"></v-radio> 
            <v-radio label="female" key="female" value="female"></v-radio> 
          </v-radio-group> 
 
          <v-layout row wrap v-if="sortAll.length>0"> 
            <v-flex xs12 sm3 md2 v-for="guide in sortAll" :key="guide.id"> 
              <v-card class="mx-2 mb-3"> 
                <v-img height="200px" :src="guide.photo"></v-img> 
 
                <v-card-title primary-title> 
                  <div> 
                    <h3 class="headline mb-0">{{guide.name}}</h3> 
                    <div> {{ guide.gender }} </div> 
                  </div> 
                </v-card-title> 
 
                <v-card-actions> 
                  <v-spacer></v-spacer> 
                  <v-btn icon> 
                    <v-icon>mdi-thumb-up</v-icon> {{ guide.rate }} 
                  </v-btn> 
                </v-card-actions> 
              </v-card> 
            </v-flex> 
          </v-layout> 
 
        </v-container> 
      </v-content> 
    </v-app> 
  </div> 
 
 
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.min.js"></script> 
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.1.0/vuex.min.js"></script> 
  <script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script> 
  <script> 
    var store = new Vuex.Store({ 
      state: { 
        guides: [{ 
            id: 1, 
            popularGuide: true, 
            name: 'Steve', 
            rate: '41', 
            gender: 'male', 
            photo: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Steve_Jobs_WWDC07.jpg/609px-Steve_Jobs_WWDC07.jpg' 
          }, 
          { 
            id: 2, 
            popularGuide: true, 
            name: 'Steve', 
            rate: '32', 
            gender: 'male', 
            photo: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Steve_Jobs_WWDC07.jpg/609px-Steve_Jobs_WWDC07.jpg' 
          }, 
          { 
            id: 3, 
            popularGuide: true, 
            name: 'Steve', 
            rate: '56', 
            gender: 'male', 
            photo: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Steve_Jobs_WWDC07.jpg/609px-Steve_Jobs_WWDC07.jpg' 
          }, 
          { 
            id: 4, 
            popularGuide: true, 
            name: 'Marilyn', 
            rate: '112', 
            gender: 'female', 
            photo: 'https://cdn.pixabay.com/photo/2016/03/21/15/10/marilyn-monroe-1270659_960_720.png' 
          }, 
          { 
            id: 5, 
            popularGuide: true, 
            name: 'Marilyn', 
            rate: '222', 
            gender: 'female', 
            photo: 'https://cdn.pixabay.com/photo/2016/03/21/15/10/marilyn-monroe-1270659_960_720.png' 
          }, 
          { 
            id: 6, 
            popularGuide: true, 
            name: 'Marilyn', 
            rate: '333', 
            gender: 'female', 
            photo: 'https://cdn.pixabay.com/photo/2016/03/21/15/10/marilyn-monroe-1270659_960_720.png' 
          }, 
          { 
            id: 7, 
            popularGuide: true, 
            name: 'Steve', 
            rate: '46', 
            gender: 'male', 
            photo: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Steve_Jobs_WWDC07.jpg/609px-Steve_Jobs_WWDC07.jpg' 
          }, 
          { 
            id: 8, 
            popularGuide: true, 
            name: 'Steve', 
            rate: '334', 
            gender: 'male', 
            photo: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e5/Steve_Jobs_WWDC07.jpg/609px-Steve_Jobs_WWDC07.jpg' 
          } 
        ] 
      } 
    }) 
 
 
 
    var app = new Vue({ 
      store, 
      vuetify: new Vuetify(), 
      el: '#app', 
      computed: { 
        ...Vuex.mapState(['guides']) 
      }, 
      data: function() { 
        return { 
          filterGender: 'both', 
          sortAll: [] 
        } 
      }, 
      methods: { 
        sortGuide() { 
          var self = this; 
          var all = []; 
          if (this.filterGender != 'both') { 
            all = this.guides.filter(x => x.gender == self.filterGender); 
          } else { 
            all = this.guides; 
          } 
          this.sortAll = all; 
        } 
      }, 
      mounted() { 
        this.sortGuide(); 
      } 
    }) 
  </script> 
</body> 
 
</html>

Answer 2

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

// ex.: store.js
getters: {
  getByGender: state => gender => {
    // Если не выбран пол, возвращаем весь список.
    // Либо производим фильтрацию по указанному критерию.
    return gender ?
      state.guides.filter(guide => guide.gender === gender) :
      state.guides;
  }
}

Для доступа к геттеру из компонента используется локальное вычисляемой свойство:

// ex.: component.vue
data() {
  return {
    // Пол. Изначально не выбран
    // и определен как пустая строка.
    gender: ''
  }
},
computed: {
  // Смешиваем результат mapGetters с внешним объектом computed.
  // Теперь будет доступна функция `this.getByGender`.
  ...mapGetters([
    'getByGender'
  ]),
  // Локальное вычисляемое свойство.
  filteredGuides() {
    return this.getByGender(this.gender);
  }
}
<!-- При использовании обычных радиокнопок -->
<input type="radio" v-model="gender" value="">
<input type="radio" v-model="gender" value="male">
<input type="radio" v-model="gender" value="female">
<!-- При использовании vuetify радиокнопок -->
<v-radio-group v-model="gender">
  <v-radio label="All" value=""></v-radio>
  <v-radio label="Male" value="male"></v-radio>
  <v-radio label="Female" value="female"></v-radio>
</v-radio-group>
<!-- Берем список гидов из вычисляемого поля `filteredGuides` -->
<v-flex xs4 sm4 md4 lg4 v-for="(guide, index) in filteredGuides" :key="guide.name">
  {{ guide.name }} [{{ guide.gender }}]
</v-flex>

Демо:

const guides = [{ 
  id: 1, 
  name: 'Karina', 
  gender: 'female', 
}, { 
  id: 2, 
  name: 'Nicolas', 
  gender: 'male', 
}]; 
 
const store = new Vuex.Store({ 
  state: { 
    guides: guides 
  }, 
 
  // Геттеры применяются когда нужно 
  // вернуть измененную информацию из хранилища. 
  // https://vuex.vuejs.org/ru/guide/getters.html#стиnь-обращения-как-к-методам 
  getters: { 
    getByGender: state => gender => { 
      // Если не выбран пол, возвращаем весь список. 
      // Либо производим фильтрацию по указанному критерию. 
      return gender ? 
        state.guides.filter(guide => guide.gender === gender) : 
        state.guides; 
    } 
  } 
}) 
 
new Vue({ 
  el: '#app', 
  store, 
  data: { 
    // Пол. Изначально не выбран 
    // и определен как пустая строка. 
    gender: '' 
  }, 
 
  computed: { 
    // Смешиваем результат mapGetters с внешним объектом computed. 
    // Теперь будет доступна функция `this.getByGender`. 
    // При модульном подходе без `Vuex.` только - `...mapGetters`. 
    ...Vuex.mapGetters([ 
      'getByGender' 
    ]), 
 
    // Локальное вычисляемое свойство. 
    filteredGuides() { 
      return this.getByGender(this.gender); 
    } 
  } 
})
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons'> 
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/vuetify@1.5.14/dist/vuetify.min.css'> 
 
 
<div id="app"> 
  <v-app id="inspire"> 
    <v-container> 
 
      <!-- При использовании обычных радиокнопок --> 
      <input type="radio" v-model="gender" value=""> 
      <input type="radio" v-model="gender" value="male"> 
      <input type="radio" v-model="gender" value="female"> 
 
      <!-- При использовании vuetify радиокнопок --> 
      <v-radio-group v-model="gender"> 
        <v-radio label="All" value=""></v-radio> 
        <v-radio label="Male" value="male"></v-radio> 
        <v-radio label="Female" value="female"></v-radio> 
      </v-radio-group> 
 
      <!-- Берем список гидов из вычисляемого поля `filteredGuides` --> 
      <v-flex xs4 sm4 md4 lg4 v-for="(guide, index) in filteredGuides" :key="guide.name"> 
        {{ guide.name }} [{{ guide.gender }}] 
      </v-flex> 
    </v-container> 
  </v-app> 
</div> 
 
<script src='https://cdn.jsdelivr.net/npm/vue@2.6.10'></script> 
<script src='https://cdn.jsdelivr.net/npm/vuex@2.0.0'></script> 
<script src='https://cdn.jsdelivr.net/npm/vuetify@1.5.14'></script>

PS В заголовке и тексте вопроса фигурирует checkbox, но в одном из фрагментов кода v-radio.

READ ALSO
Конфликт двух компонентов Swiper на одной странице

Конфликт двух компонентов Swiper на одной странице

Использую этот слайдерДобавляю два компонента на страницу

145
Копирование через spread-оператор с заменой поля второго уровня

Копирование через spread-оператор с заменой поля второго уровня

Всем привет, передо мной стоит задача, которую хочу решить за минимальное число символов, подробнее в коде ниже:

115
Отправка письма через smtp C++

Отправка письма через smtp C++

Искал реализацию для отправки писем через smtp, документации не нашел, пришлось по форумам бродить но нигде ничего дельного не былоНашел тему...

128
База данных в C++ [закрыт]

База данных в C++ [закрыт]

Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы он был сосредоточен только на одной проблеме

112