Неисправность при передаче переменной из возвращенного JSON в фильтр списка радио для основного поиска - PullRequest
0 голосов
/ 24 августа 2018

Прежде всего, мои извинения.Я новичок в Vue и немного борюсь.У меня есть базовый поиск, в котором я передаю ключевое слово в AWS CloudSearch, возвращаю JSON и показываю результаты.Базовый поиск по ключевым словам работает нормально.Я сейчас пытаюсь передать объект данных с именем studenttype в список радиостанций и фильтра на основе этого.Все работало, когда я работал с заглушенными поддельными данными во внешнем файле данных, но теперь, когда я получаю реальные данные, это не так.Я знаю, что должен получить данные от Axios, а затем опубликовать их в качестве опции в TypeFilter.vue.Я просто не знаю, как это сделать.Спасибо за вашу помощь.

Вот мой файл App.vue:

<template>
    <div class="app search">
        <!-- Search header -->
        <header id="searchHeader" class="search--header py-2 py-md-4">
            <div class="container">
                <div class="input-group">
                    <!-- Type filter -->
                    <TypeFilter v-model="studenttype" />

                    <!-- Location filter -->
                    <LocationFilter v-model="state" />

                    <!-- Search box -->
                    <SearchBox v-model="searchTerm"/>

                    <!-- More filters -->
                    <!--<div class="dropdown checkbox-dropdown mx-2">
                        <button class="btn btn-lg btn-white py-3 px-4 dropdown-toggle" type="button" id="dropdownMenuButtonFilters" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">More Filters</button>
                        <div class="dropdown-menu" aria-labelledby="dropdownMenuButtonFilters">
                        </div>
                    </div>-->

                    <!-- Search button -->
                    <button v-on:click="searchSubmit(searchTerm)" class="btn btn-lg btn-white ml-2 px-4 search-submit">Search</button>
                </div>

                <!-- Active filters (hidden for v0) -->
                <!--<div class="search--header--filters mt-3">
                    <span class="badge">Filter</span>
                    <span class="badge">Filter</span>
                    <span class="badge">Filter</span>
                </div>-->
            </div>
        </header>

        <!-- Main results -->
        <div class="container">
            <!-- Result count and show/sort -->
            <ResultCount v-model="page" :items="schools.length" :perPage="10"/>

            <!-- Results -->
            <SchoolList :schools="pageOfSchools"/>

            <!-- Pagination -->
            <Pagination v-model="page" :items="schools.length" :perPage="10"/>
        </div>
    </div>
</template>

<script>
    import SchoolList from './SchoolList'
    import ResultCount from './ResultCount'
    import Pagination from './Pagination'
    import SearchBox from './SearchBox'
    import TypeFilter from "./TypeFilter";
    import LocationFilter from "./LocationFilter";
    import getArraySection from '../utilities/get-array-section'
    export default {
        name: 'app',
        components: {SchoolList, ResultCount, Pagination, SearchBox, TypeFilter, LocationFilter},
        data: () => ({
            searchTerm: '',
            studenttype: '',
            state: '',
            schools: [],
            page: 1,
        }),
        computed: {
            pageOfSchools: function () {
                return getArraySection(this.schools, this.page, 10)
            }
        },
        watch: {
            studenttype: function () {
                this.filterSchools()
            },
            state: function () {
                this.filterSchools()
            }
        },

        methods: {
            searchSubmit: function(terms) {
                axios.post("/search/college", {
                    "search": {
                        terms: terms.split(' ')
                    }
                })
                    .then(response => {
                        this.schools = response.data.hit
                        console.log(response.data)
                    })
            },

            filterSchools: function () {
                const searchTerm = this.searchTerm.toLowerCase()
                const studenttype = this.studenttype

                if (searchTerm) {
                    result = result.filter(school => {
                        return (
                            school.title.toLowerCase().search(searchTerm) >= 0 ||
                            school.location.toLowerCase().search(searchTerm) >= 0
                        )
                    })
                }

                if (studenttype) {
                    result = result.filter(school => school.studenttype.indexOf(studenttype) >= 0)
                }

                this.schools = result
                this.page = 1
            }
        },
        created: function () {
            this.filterSchools()
        }
    }
</script>

Вот мой файл TypeFiler.vue с фильтром:

<template>
  <div class="dropdown checkbox-dropdown d-none d-md-inline-block mr-2">
    <button class="btn btn-lg btn-white py-3 px-4 dropdown-toggle" type="button" id="dropdownMenuButtonType" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Choose Type</button>
    <div class="dropdown-menu" aria-labelledby="dropdownMenuButtonType">
      <template v-for="option in options">
        <div class="custom-control custom-radio">
          <input class="custom-control-input" type="radio" :value="option" :name="name" v-model="selected">
          <label class="custom-control-label" v-if="option === ''">All</label>
        </div>
      </template>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'checkbox-group',
    props: {
      value: {
        default: ''
      },
      options: {
        type: Array,
        default: () => ['', ...Object.keys(???)]
      },
      name: {
        type: String,
        default: 'type-filter'
      }
    },
    data: function() {
      return { selected: this.value }
    },
    watch: {
      selected: function(val) {
        this.$emit('input', val)
      }
    }
  }
</script>

Вотпример JSON, который я получаю:

{
    "found": 18,
    "start": "0",
    "cursor": "",
    "returned": 18,
    "hit": [{
        "name": "State Peter Pan Institute",
        "city": "New Burniceshire",
        "state": "Illinois",
        "areasofstudy": "Bachelor's",
        "degreetype": "BACHELORS",
        "studenttype": "UG",
        "schoolsnprograms": "state",
        "schoolsize": "1",
        "isCustomer": "0",
        "schoolUrl": "http://localhost/school/10/State Peter Pan Institute",
        "schoolLogo": 10
    }, {
        "name": "State Flatland University",
        "city": "New Ulices",
        "state": "Maryland",
        "areasofstudy": "Bachelor's",
        "degreetype": "BACHELORS",
        "studenttype": "UG",
        "schoolsnprograms": "state",
        "schoolsize": "1",
        "isCustomer": "0",
        "schoolUrl": "http://localhost/school/75/State Flatland University",
        "schoolLogo": 75
    }, {
        "name": "State Applewood Halls of Ivy",
        "city": "East Karimouth",
        "state": "West Virginia",
        "areasofstudy": "Bachelor's",
        "degreetype": "BACHELORS",
        "studenttype": "UG",
        "schoolsnprograms": "state",
        "schoolsize": "1",
        "isCustomer": "0",
        "schoolUrl": "http://localhost/school/89/State Applewood Halls of Ivy",
        "schoolLogo": 89
    }]
}

Ответы [ 2 ]

0 голосов
/ 24 августа 2018

Итак, вы хотите, чтобы studenttype было 2-way data binding. Вы можете достичь этого с :sync в Vue.

<TypeFilter :studenttype.sync="studenttype" />

Ваш TypeFilter компонент должен принимать studenttype в качестве свойства:

props: {
  studenttype: {
    type: String,
    default: null
  }
}

TypeFilter не знает обо всех student types, которые он должен иметь для фильтрации. Таким образом, вам нужно будет пройти те. Один из способов сделать это - с помощью вычисляемого свойства в parent component (App.vue):

computed: {
  studentTypes: {
    get: function() {
      return this.schools.map(function(school) {
        return school.studenttype
      })
    }
  }
}

Теперь мы можем предоставить это computed getter в качестве значения привязки для нашего свойства options в нашем компоненте TypeFilter.vue.

<TypeFilter :studenttype.sync="studenttype" ::options="studentTypes"/>

Далее, когда радио меняется, вам нужно передать это значение родителю. Поскольку у вас уже есть настройка watcher на вашем входе, вам нужно сделать только одно небольшое изменение для поддержки привязки данных 2-way:

this.$emit('udpate:studenttype', val)

Когда вы нажимаете радио, родительское значение (App.vue) studenttype будет обновлено, чтобы отразить выбор в дочернем элементе (TypeFilter.vue). Эта привязка будет работать между обоими компонентами, и никаких манипуляций не требуется.

Теперь, когда у вас есть studenttype и у нас есть массив со списком школ, мы можем использовать вычисляемый метод получения, чтобы определить, какие школы должны быть видны (в App.vue):

visibleSchools: function() {
   switch(true) {
      case this.studenttype:
        return this.schools.filter(function(school) {
          return school.studenttype === this.studenttype
        })
        break
      default:
        return this.schools
   }
}

Наконец, передайте visibleSchools вашему SchoolsList компоненту, и это покажет одно из следующих обстоятельств:

  • Только школы, соответствующие studenttype, если studenttype является правдивым или
  • Все школы, если не установлено studenttype.
0 голосов
/ 24 августа 2018

Хорошо, давайте сделаем это шаг за шагом:

Сначала мы должны получить начальный список школ к axios:

searchSubmit: function(terms) {
  axios.post("/search/college", {
      "search": {
        terms: terms.split(' ')
      }
    })
    .then(response => {
      this.schools = response.data.hit
      console.log(response.data)
    })
}

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

computed: {
  allStudentTypes: function() {
    // checking if schools value is already available
    if (this.schools.hit) {
      let allStudentTypes = this.schools.hit.map(school => school.studenttype)
      // now we'll get unique values only
      let filteredStudentTypes = [...new Set(allStudentTypes)]
      return filteredStudentTypes
    } else {
      return []
    }
  }
}

Затем мы передадим это значение компоненту TypeFilter:

<TypeFilter :options='allStudentTypes' v-model="studenttype" />

TypeFilter компонент выполнит свою работу и передаст переменную studenttype корневому компоненту.

Итак, теперь мы собираемся отфильтровать школы, я бы посоветовал вам не переписывать schools данных, давайте вместо этого сделаем это в вычисляемом разделе:

computed: {
  allStudentTypes: ...,
  filteredSchools: function() {
    const searchTerm = this.searchTerm.toLowerCase()
    const studenttype = this.studenttype
    let result = this.schools

    if (searchTerm) {
      result = result.filter(school => {
        return (
          school.title.toLowerCase().search(searchTerm) >= 0 ||
          school.location.toLowerCase().search(searchTerm) >= 0
        )
      })
    }

    if (studenttype) {
      result = result.filter(school => school.studenttype.indexOf(studenttype) >= 0)
    }

    return result
  }
}

Так что теперь мы можем передать filteredSchools, когда захотим.

И мы также можем удалить this.filterSchools() из created и watch секций.

...