Фильтровать массив на основе нескольких опций (Vue / JavaScript) - PullRequest
0 голосов
/ 07 марта 2019

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

У меня есть 4 вычисленных свойства:

  • FilterResults: где происходит фильтрация
  • фазы: сбор всех фаз на основе результатов
  • результаты: исходный список результатов (сохраненный в Vuex)
  • состояний: сбор всех состояний на основе результатов

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

Код

<template>
  <div class="results">
    <Banner/>
    <div class="container">
      <div class="columns">
        <main role="main" class="column is-8-tablet is-9-widescreen">
          <p class="title is-4">Results for: {{ $route.query.q }}</p>
          <p class="subtitle">{{ results.length }} Trials Avaliable</p>
          <ul>
            <li v-for="trial in results" :key="trial.studyid">
              <div class="card" :data-location="trial.state" :data-phases="trial.phasename">
                <div class="card-content">
                  <div class="content">
                    <h2 class="title is-4">
                      <a href="void:javascript(0)" @click="goToDetail(trial.studyname)">
                        {{ trial.studyname }}
                      </a>
                    </h2>
                    <p>{{ trial.protocoltitle.replace('�', '') }}</p>
                    <p>Available in {{ trial.studyentitylocation.split('`').length -1 }} location(s)</p>
                  </div>
                </div>
              </div>
            </li>
          </ul>
        </main>
        <aside role="complementary" class="column is-4-tablet is-3-widescreen">
          <p class="title is-4">Filter Options</p>
          <button class="accordion">Locations</button>
          <div class="panel">
            <form>
              <div class="control">
                <label class="radio">
                  <input type="radio" name="states" value="All" v-model="checkedLocations">
                  All
                </label>
                <label class="radio" v-for="(state, i) in states" :key="i">
                  <input type="radio" name="states" :value="state" v-model="checkedLocations">
                  {{ state }}
                </label>
              </div>
            </form>
          </div>
          <button class="accordion">Phase</button>
          <div class="panel">
            <form>
              <div class="control">
                <label class="radio">
                  <input type="radio" name="phases" value="All" v-model="checkedPhases">
                  All
                </label>
                <label class="radio" v-for="(phase, i) in phases" :key="i">
                  <input type="radio" name="phases" :value="phase" v-model="checkedPhases">
                  Phase {{ phase }}
                </label>
              </div>
            </form>
          </div>
        </aside>
      </div>
    </div>
  </div>
</template>

<script>
import Banner from '@/components/Banner'

export default {
  name: 'Results',
  components: {
    Banner
  },
  data () {
    return {
      checkedLocations: 'All',
      checkedPhases: 'All'
    }
  },
  mounted () {
    this.activateAccordion()
  },
  computed: {
    results () {
      return this.$store.state.results
    },
    states () {
      let statesArray = []
      this.results.forEach((result) => {
        if (result.state) {
          var state = result.state

          state.forEach((item) => {
            if (statesArray.indexOf(item) === -1) {
              statesArray.push(item)
            }
          })
        }
      })
      return statesArray.sort()
    },
    phases () {
      let phaseArray = []
      this.results.forEach((result) => {
        if (result.phasename) {
          var phase = result.phasename

          phase.forEach((item) => {
            if (phaseArray.indexOf(item) === -1) {
              phaseArray.push(item)
            }
          })
        }
      })
      return phaseArray.sort()
    },
    filteredResults () {
      let results = ''
      if (this.checkedLocations !== 'All') {
        results = this.results.filter((result) => result.state.includes(this.checkedLocations))
        return results
      } else {
        return this.results
      }
    }
  }
}
</script>

Вот как приложение выглядит в интерфейсе Trials App

Я также новичок в современном синтаксисе JavaScript, так что, пожалуйста, будьте милы.

Ответы [ 2 ]

0 голосов
/ 13 марта 2019

Я создал codepen , чтобы попытаться показать, как этого можно добиться. Есть список элементов, содержащих carID и cityID. Кроме того, есть два выбора для фильтрации результата. Когда вы изменяете выбор, он также фильтрует параметры другого выбора. Я надеюсь, что это может помочь вам, если у вас есть какие-либо вопросы, просто спросите.

const data = [
  {
   cityID: 1,
   carID:1,
   name: 'Ted'
  },
  {
   cityID: 1,
   carID:2,
   name: 'Tod'
  },
  {
   cityID: 2,
   carID:1,
   name: 'Michel'
  },
 {
   cityID: 3,
   carID:1,
   name: 'Romeu'
  },
  {
   cityID: 2,
   carID:3,
   name: 'Thomas'
  },
  {
   cityID: 3,
   carID:4,
   name: 'Lucy'
  },
  {
   cityID: 4,
   carID:1,
   name: 'Mary'
  },
]

const cities = [{ cityID: 1, name:'New York'},{ cityID: 2, name:'Sydney'}, { cityID: 3, name:'Chicago'},{ cityID: 4, name:'Perth'}]
const cars = [{ carID: 1, name:'Cruze'},{ carID: 2, name:'Mustang'}, { carID: 3, name:'Blazer'},{ carID: 4, name:'Tucson'}]

new Vue({
  el: '#app',
  data: function() {
    return {
      data,
      cities,
      cars,
      city: "",
      car: "",
    }
  },
  methods: {
    findCarName: function (carID) {
      return this.cars.find(car => car.carID === carID).name
    },
    findCityName: function (cityID) {
      return this.cities.find(city => city.cityID === cityID).name
    },
    reset: function () {
      this.city = ""
      this.car = ""
    }
    
  }, 
  computed: {
    filteredData: function() {
      let resultData = this.data
      if (this.city) {
        resultData = resultData.filter(item => item.cityID === this.city)
      }
      if (this.car) {
        resultData = resultData.filter(item => item.carID === this.car)
      }
      return resultData
    },
    
    filteredCars: function () {
      const carIDs = this.filteredData.reduce((acc, next) => {
        if (acc.indexOf(next.carID) === -1){
          return [...acc, next.carID]  
        }
        return acc
      },[])
      
      if (carIDs.length) {
        return carIDs.map(carID => ({carID, name: this.findCarName(carID)}))
      }
      return this.cars
    },
    
    filteredCities: function () {
      const citiesIDs = this.filteredData.reduce((acc, next) => {
        if (acc.indexOf(next.cityID) === -1){
          return [...acc, next.cityID]  
        }
        return acc
      },[])
      
      if (citiesIDs.length) {
        return citiesIDs.map(cityID => ({cityID, name: this.findCityName(cityID)}))
      }
      return this.cities
    }
  }
  
})
#app {
  margin: 30px;
}
#app .form-group {
  display: flex;
  align-items: center;
}
#app .form-group label {
  font-weight: bold;
  color: #337ab7;
  margin-right: 20px;
}
#app .filters {
  margin-bottom: 20px;
  display: flex;
  width: 700px;
  justify-content: space-around;
}
#app .table {
  width: 700px;
}
#app .table thead tr td {
  font-weight: bold;
  color: #337ab7;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div class="filters row">
    <div class="form-group">
       <label for="city">City</label>
        <select v-model="city" id="city" class="form-control">
          <option value="">Select City</option>
          <option v-for="item in filteredCities" :key="item.cityID" :value="item.cityID">{{item.name}}</option>
         </select>
      
    </div>  
    <div class="form-group">
      <label for="car">Car</label>    
      <select v-model="car" id="car" class="form-control">
      <option value="">Select Car</option>
      <option v-for="item in filteredCars" :key="item.carID" :value="item.carID">{{item.name}}</option>
      </select>
    </div>
    <div class="form-group">
      <button type="button" class="btn btn-primary" @click="reset">Reset</button>
    </div>
    
  
  </div>
  <table class="table table-striped table-bordered">
    <thead>
      <tr><td>Name</td><td>Car</td><td>City</td></tr>
    </thead>
    <tbody>
      <tr v-for="item in filteredData" :key="data.name">
        <td>{{item.name}}</td>
        <td>{{findCarName(item.carID)}}</td>
        <td>{{findCityName(item.cityID)}}</td>
      </tr>
    </tbody>
  </table>
<div>
  
  
  
0 голосов
/ 07 марта 2019

Если я вас понимаю, похоже, что вы можете просто добавить еще один фильтр в соответствии с установленным флажком, аналогично тому, который у вас уже есть?

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