Как отфильтровать JSON объектов массива из нескольких атрибутов в javascript - PullRequest
0 голосов
/ 28 апреля 2020

В настоящее время я борюсь с небольшим приложением VueJS для фильтрации ответов API по множеству значений на основе раскрывающихся списков.

Я мог бы управлять двумя фильтрами, если бы один был объявлен вне if (filtered) и второе условие, объявленное внутри.

Однако мне интересно, как обстоит дело, например, с более чем двумя вариантами. Код прилагается ниже.

// Trunkera beskrivning
Vue.filter("truncate", function (value, limit) {
  if (value.length > limit) {
value = value.substring(0, limit - 3) + "...";
  }
  return value;
});

new Vue({
  el: "#app",
  data: function () {
return {
  visible: false,
  boats: null,
  filter: {
    options: {
      brands: [],
      model: [],
      engineBrands: [],
      engineModels: [],
      type: [],
      maxPrice: null,
      minPrice: null,
      years: [],
    }
  },
  selected: {
    options: {
      brand: null,
      length: 1000,
      condition: null,
      engineBrand: null,
      engineModel: null,
      engineType: null,
      fridge: null,
      kitchen: null,
      type: null,
      shower: null,
      year: null,
      water: null,
      wc: null
    }
  }
};
  },
  created() {
const vm = this;
fetch(
    'https://www.sokbat.se/api/Ad?json=%7b"CompanyId":"5055","AdCategoryId":"10","SortOrder":0,"StartAd":0,"NumberOfAds":0%7d'
  )
  .then((response) => {
    return response.json();
  })
  .then((data) => {
    let arr = [];
    // fyll på båtar
    vm.boats = data;
    // forEach...hämta detaljer
    /*data.forEach((boat) => {
      fetch(`https://www.sokbat.se/api/ad/${boat.AdId}`)
        .then((response) => {
          arr.push(response.json())
      })
    })*/
    this.calcAttributes(data);
    //vm.boats = arr;
  });
  },
  computed: {
computed_items: function () {
  const vm = this;
  let filterType = this.selected.options.type,
    filterEngineModel = this.selected.options.engineModel,
    filterBrand = this.selected.options.brand,
    // Ranges
    filterPrice = this.selected.options.price,
    filterYear = this.selected.options.year,
    filterLength = this.selected.options.length,
    filterWidth = this.selected.options.width;

  return this.boats.filter(function (item) {
    let filtered = true;

    if (filtered) {
      // Båttyp
      if (filterType && filterType.length > 0) {
        filtered = item.MotoBoatTypeSelectionCaption == filterType;
      }
      // Märke
      if (filterBrand && filterBrand.length > 0) {
        filtered = item.Brand == filterBrand;
      }
      // Båtmotor
      if (filterEngineModel && filterEngineModel.length > 0) {
        filtered = item.EngineModel == filterEngineModel;
      }
      // Motorår
      if (filterYear && filterYear != "") {
        filtered = item.BoatYear == filterYear;
      }
      /* Pris
      if (filterPrice && filterPrice[0] > vm.filter.options.minPrice) {
        filtered = item.Price >= filterPrice[0]
      }
      // Längd
      if (filterWidth && filterWidth[0] >= vm.filter.options.minWidth) {
        filtered = item.Width >= filterWidth[0]
      }
      if (filterLength && filterLength[0] >= vm.filter.options.minLength) {
        filtered = item.Length >= filterLength[0]
      }*/
    }
    return filtered;
  });
}
  },
  mounted: function () {
const vm = this;
let i = 0;
this.$watch('selected', function () {
  console.log(vm.computed_items);
}, {deep:true})
  },
  methods: {
calcAttributes(data) {
  const vm = this;
  let tmp_brands = [],
    tmp_models = [],
    tmp_yrs = [],
    tmp_width = [],
    tmp_types = [];

  data.forEach((item) => {
    tmp_brands.push(item.Brand);
    tmp_models.push(item.EngineModel);
    tmp_yrs.push(item.BoatYear);
    tmp_types.push(item.MotoBoatTypeSelectionCaption)
  });

  let maxPrice = 0,
    minPrice = 0,
    minWidth = 0,
    maxWidth = 0,
    minLength = 0,
    maxLength = 0;
  data.forEach(item => {
    if (item.Price >= maxPrice) {
      maxPrice = item.Price
    }
    if (item.Price <= maxPrice) {
      minPrice = item.Price
    }
    //
    if (item.Width >= maxWidth) {
      maxWidth = item.Width
    }
    if (item.Width <= minWidth) {
      minWidth = item.Width
    }
    //
    if (item.Length >= maxLength) {
      maxLength = item.Length
    }
    if (item.Length <= minLength) {
      minLength = item.Length
    }
  });
  // min/max bredd
  // unique's
  vm.filter.options.maxPrice = maxPrice;
  vm.filter.options.minPrice = minPrice;
  //
  vm.filter.options.maxWidth = maxWidth;
  vm.filter.options.minWidth = minWidth;
  vm.filter.options.type = Array.from(new Set(tmp_types));
  //
  vm.filter.options.maxLength = maxLength;
  vm.filter.options.minLength = minLength;
  vm.filter.options.brands = Array.from(new Set(tmp_brands))
  vm.filter.options.engineModels = Array.from(new Set(tmp_models))
  vm.filter.options.years = Array.from(new Set(tmp_yrs));
}
  }
});
[v-cloak]{display:none}body{font-family:Ubuntu}.filter-box{background:#333;border-radius:5px;padding:1rem;margin:2rem}.results{padding:1rem;margin:2rem}.el-row{margin-bottom:20px}.el-row:last-child{margin-bottom:0}.el-col{border-radius:4px}.bg-purple-dark{background:#99a9bf}.bg-purple{background:#d3dce6}.bg-purple-light{background:#e5e9f2}.grid-content{border-radius:4px;min-height:36px}.row-bg{padding:10px 0;background-color:#f9fafc}.el-select{width:100%}.el-input__inner{color:#333!important}.inline>p{color:#fff;margin:0;padding:0}.boat-card{margin:10px}.time{font-size:16px;line-height:20px;color:#999}.time p{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.time p br{display:none}.bottom{margin-top:13px;line-height:12px}.button{padding:0;float:right}.image{width:100%;display:block}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}input::placeholder{color:#333!important}.el-col.el-col-8.el-col-xs-24.el-col-sm-12.el-col-md-8.el-col-lg-6{min-height:350px}.fade-enter-active,.fade-leave-active{transition:opacity .5s}.fade-enter,.fade-leave-to{opacity:0}a{text-decoration:none}
<div id="app" v-cloak>

  <div class="filter-box">

    <el-row :gutter="20">
      <el-col :span="6">
        <el-select v-model="selected.options.brand" placeholder="Märke">
          <el-option default label="Alla" value=""></el-option>
          <el-option v-for="item in filter.options.brands" :key="item" :label="item" :value="item">
          </el-option>
        </el-select>
      </el-col>

      <el-col :span="12">
        <div class="inline">
          <p>Pris</p>
          <el-slider v-model="selected.options.price" range :min="filter.options.minPrice" :max="filter.options.maxPrice">
          </el-slider>
        </div>
      </el-col>

      <el-col :span="6">
        <el-select v-model="selected.options.engineModel" placeholder="Motormodell">
          <el-option default label="Alla" value=""></el-option>
          <el-option v-for="item in filter.options.engineModels" :key="item" :label="item" :value="item">
          </el-option>
        </el-select>
      </el-col>

    </el-row>


    <el-row :gutter="20">
      <el-col :span="6">
        <el-select v-model="selected.options.type" placeholder="Båttyp">
          <el-option default label="Alla" value=""></el-option>
          <el-option v-for="item in filter.options.type" :key="item" :label="item" :value="item">
          </el-option>
        </el-select>
      </el-col>

      <el-col :span="6">
        <div class="inline">
          <p>Bredd</p>
          <el-slider v-model="selected.options.width" range :min="filter.options.minWidth" :max="filter.options.maxWidth">
          </el-slider>
        </div>
      </el-col>

      <el-col :span="6">
        <div class="inline">
          <p>Längd</p>
          <el-slider v-model="selected.options.length" range show-stops :min="filter.options.minLength" :max="filter.options.maxLength">
          </el-slider>
        </div>
      </el-col>

      <el-col :span="6">
        <el-select v-model="selected.options.year" placeholder="År">
          <el-option default label="Alla" value=""></el-option>
          <el-option v-for="item in filter.options.years" :key="item" :label="item" :value="item">
          </el-option>
        </el-select>
      </el-col>

    </el-row>

  </div>

  <div v-if="boats.length > 1" class="results">
    <el-row>

      <el-col v-for="(boat, i) in computed_items" :span="8" :key="i" :xs="8" :sm="8" :md="8" :lg="6">
        <transition name="fade">
          <a :href="`https://marine.local/bat/?id=${boat.AdId}`" target="_blank">
            <el-card class="boat-card" :body-style="{ padding: '8px' }" shadow="hover">
              <img :src=`${boat.AdResourceURI}` class="image">
              <div style="padding: 14px;">
                <span>{{boat.AdTitle}}</span>
                <div class="bottom clearfix">
                  <time class="time" :inner-html.prop="boat.AdIntroduction | truncate(60)"></time>
                  <el-button type="text" class="button">
                    {{boat.Price.toLocaleString('sv-SE', { style: 'currency', currency: 'SEK' })}}
                  </el-button>
                </div>
              </div>
            </el-card>
          </a>
        </transition>

      </el-col>

    </el-row>
  </div>

</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" rel="stylesheet" />
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

1 Ответ

1 голос
/ 28 апреля 2020

У вас уже есть фильтры в data.filter.options. Используй их. Возможно, вам потребуется добавить minLength, maxLength и некоторые другие.

Вы также должны убедиться, что имена этих переменных в this.filter.options соответствуют переменным в ваших лодках, например, brand вместо brands.

И я бы сделал год значением диапазона (min-max) вместо массива. До вас.

computed: {
  filtered_boats: function () {
    let filtered = this.boats;

    // the minimums
    let mins = {
      "minPrice": 'price',
      "minLength": 'length',
      ...
    };
    filtered = Object.keys(mins).forEach(k => if (this.filter.options[k] !== null) filtered = filtered.filter(boat => boat[mins[k]] >= this.filter.options[k]));

    // the maximums
    let maxs = {
      "maxPrice": 'price',
      "maxLength": 'length',
      ...
    };
    filtered = Object.keys(maxs).forEach(k => if (this.filter.options[k] !== null) filtered = filtered.filter(boat => boat[maxs[k]] <= this.filter.options[k]));

    // the multi-value filters
    let fields = ['brand', 'model', 'type', ...];
    filtered = fields.forEach(f => if (this.filter.options[f].length > 0) filtered = filtered.filter(boat => this.filter.options[f].indexOf(boat[f]) != -1));

    return filtered;
  }
}

Извините, я не смог проверить код. Но я надеюсь, что вы поняли идею!

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