Фильтрация списка элементов

151
02 августа 2018, 12:50

Помогите реализовать фильтрацию имеющегося списка.

Задача состоит в том, что после изменения соответствующего селекта или чек-бокса метод dispalyCars каждый раз должен отрисовывать в DOM необходимое количество элементов с классом cars-list__item.

var dataController = (function() { 
  var cars = [{ 
      brand: 'Toyota', 
      year: 2012, 
      price: 600000, 
      owners: 2, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Audi', 
      year: 2002, 
      price: 350000, 
      owners: 3, 
      features: { 
        transmission: 'manual', 
        ac: false 
      } 
    }, 
 
    { 
      brand: 'Ford', 
      year: 2015, 
      price: 500000, 
      owners: 1, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Volkswagen', 
      year: 1992, 
      price: 99999, 
      owners: 6, 
      features: { 
        transmission: 'manual', 
        ac: false 
      } 
    }, 
 
    { 
      brand: 'Volkswagen', 
      year: 2005, 
      price: 450000, 
      owners: 3, 
      features: { 
        transmission: 'manual', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Toyota', 
      year: 2017, 
      price: 900000, 
      owners: 1, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'BMW', 
      year: 2010, 
      price: 750000, 
      owners: 3, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Ford', 
      year: 2012, 
      price: 520000, 
      owners: 3, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Audi', 
      year: 2000, 
      price: 250000, 
      owners: 5, 
      features: { 
        transmission: 'manual', 
        ac: false 
      } 
    }, 
 
    { 
      brand: 'Subaru', 
      year: 2013, 
      price: 750000, 
      owners: 1, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
  ]; 
 
  return { 
    getData: function() { 
      return cars; 
    } 
  } 
})(); 
 
var UIcontroller = (function() { 
 
  return { 
    dispalyCars: function(carsList) { 
 
      var carsBlock = document.querySelector('.cars-list'); 
 
      var fragment = document.createDocumentFragment(); 
 
      for (var i = 0; i < carsList.length; i++) { 
 
        if (carsList[i].features.transmission === 'auto') { 
          carsList[i].features.transmission = 'автомат'; 
        } else { 
          carsList[i].features.transmission = 'механическая'; 
        }; 
 
        if (carsList[i].features.ac === true) { 
          carsList[i].features.ac = 'да'; 
        } else { 
          carsList[i].features.ac = 'нет'; 
        }; 
 
        var newCar = document.createElement('li'); 
        newCar.className = 'cars-list__item'; 
        newCar.textContent = 'Марка: ' + carsList[i].brand + ', Год выпуска: ' + carsList[i].year + ', Цена: ' + carsList[i].price + ' руб. ' + 'Собственников по ПТС: ' + carsList[i].owners + '. Дополнительно ' + '(' + 'коробка: ' + carsList[i].features.transmission + ', кондиционер: ' + carsList[i].features.ac + ')'; 
 
        fragment.appendChild(newCar); 
      } 
      carsBlock.appendChild(fragment); 
 
    } 
  } 
})(); 
 
var controller = (function(dataCtrl, UICtrl) { 
 
  // Получить массив с данными 
  var carsList = dataCtrl.getData(); 
 
  // Отрисовать список авто 
  UICtrl.dispalyCars(carsList); 
 
})(dataController, UIcontroller);
.cars-list { 
  padding: 0; 
  margin: 0; 
  min-height: 360px; 
} 
 
.cars-list__item { 
  background-color: rgba(64, 161, 241, 0.753); 
  box-sizing: border-box; 
  width: 1000px; 
  height: 30px; 
  margin-top: 5px; 
  margin-bottom: 5px; 
  padding-top: 5px; 
  padding-left: 5px; 
  border-radius: 10px; 
  list-style: none; 
} 
 
.filter { 
  background-color: silver; 
  width: 1000px; 
  height: 30px; 
  margin-top: 20px; 
  padding-top: 5px; 
  padding-left: 5px; 
  border-radius: 10px; 
}
<div class="main"> 
  <ul class="cars-list"></ul> 
  <form action="#" class="filter" autocomplete="off"> 
    <select name="barnd" id="brand-type" class="filter__brand"> 
      <option value="any" selected>Любaя марка</option> 
      <option value="toyota">Toyota</option> 
      <option value="audi">Audi</option> 
      <option value="ford">Ford</option> 
      <option value="volkswagen">Volkswagen</option> 
      <option value="bmw">BMW</option> 
      <option value="subaru">Subaru</option> 
    </select> 
 
    <select name="year" id="cars-year" class="filter__year"> 
      <option value="any" selected>Любой год выпуска</option> 
      <option value="1">до 2000 года</option> 
      <option value="2">до 2010 года</option> 
      <option value="3">после 2010 года</option> 
    </select> 
 
    <select name="price" id="cars-price" class="filter__price"> 
      <option value="any" selected>Любая цена</option> 
      <option value="low">до 100000&#x20bd;</option> 
      <option value="middle">100000 - 500000&#x20bd;</option> 
      <option value="high">от 500000&#x20bd;</option> 
    </select> 
 
    <select name="owners" id="cars-owners" class="filter__owners"> 
      <option value="any" selected>Любое число собственников</option> 
      <option value="1">Один</option> 
      <option value="2">Два</option> 
      <option value="3">Три и более</option> 
    </select> 
 
    <input type="checkbox" name="features" value="auto" id="transmisson"> 
    <label class="feature feature--auto" for="transmisson">Автоматическая коробка передач</label> 
 
    <input type="checkbox" name="features" value="yes" id="conditioner"> 
    <label class="feature feature--conditioner" for="conditioner">Кондиционер</label> 
  </form> 
</div>

Answer 1

Если нужно отфильтровать массив - можно воспользоваться функцией filter

var filtered = carsList.filter(car => condition1 && condition2 && ...)

Где вместо conditionN идет проверка нужных свойств в соответствии с выбранными элементами в селекте.

после фильтрации нужно просто передать полученный массив в функцию UICtrl.dispalyCars. Стоит заметить, что данная функция не очищает предварительно блок .cars-list, что может привести к дублированию элементов. Поэтому это нужно либо добавить в саму функцию, либо сделать перед ее вызовом.

Саму фильтрацию следует производить в обработчиках change нужных селектов и чекбоксов.

Answer 2

В общем работает, но есть только необходимость сделать фильтрацию по чек-боксам более универсальной на тот случай, если их будет гораздо больше, чем 2

var dataController = (function() { 
  var cars = [{ 
      brand: 'Toyota', 
      year: 2012, 
      price: 600000, 
      owners: 2, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Audi', 
      year: 2002, 
      price: 350000, 
      owners: 3, 
      features: { 
        transmission: 'manual', 
        ac: false 
      } 
    }, 
 
    { 
      brand: 'Ford', 
      year: 2015, 
      price: 500000, 
      owners: 1, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Volkswagen', 
      year: 1992, 
      price: 99999, 
      owners: 6, 
      features: { 
        transmission: 'manual', 
        ac: false 
      } 
    }, 
 
    { 
      brand: 'Volkswagen', 
      year: 2005, 
      price: 450000, 
      owners: 3, 
      features: { 
        transmission: 'manual', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Toyota', 
      year: 2017, 
      price: 900000, 
      owners: 1, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'BMW', 
      year: 2010, 
      price: 750000, 
      owners: 3, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Ford', 
      year: 2012, 
      price: 520000, 
      owners: 3, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    }, 
 
    { 
      brand: 'Audi', 
      year: 2000, 
      price: 250000, 
      owners: 5, 
      features: { 
        transmission: 'manual', 
        ac: false 
      } 
    }, 
 
    { 
      brand: 'Subaru', 
      year: 2013, 
      price: 750000, 
      owners: 1, 
      features: { 
        transmission: 'auto', 
        ac: true 
      } 
    } 
  ]; 
  console.log(cars); 
  return { 
    getData: function() { 
      return cars; 
    } 
  } 
})(); 
 
var UIcontroller = (function() { 
 
  return { 
    dispalyCars: function(carsList) { 
 
      var carsBlock = document.querySelector('.cars-list'); 
 
      var fragment = document.createDocumentFragment(); 
 
        carsList.forEach(function(item){ 
 
        var newCar = document.createElement('li'); 
        newCar.className = 'cars-list__item'; 
        newCar.textContent = 'Марка: ' + item.brand + ', Год выпуска: ' + item.year + ', Цена: ' + item.price + ' руб. ' + 'Собственников по ПТС: ' + item.owners + '. Дополнительно ' + '(' + 'коробка: ' + item.features.transmission + ', кондиционер: ' + item.features.ac + ')'; 
 
        fragment.appendChild(newCar); 
      }); 
 
      carsBlock.appendChild(fragment); 
 
    }, 
 
    filterData: function(carsList) { 
 
      var brand = document.querySelector('.filter__brand'); 
      var year = document.querySelector('.filter__year'); 
      var price = document.querySelector('.filter__price'); 
      var owners = document.querySelector('.filter__owners'); 
      var features = document.getElementsByName('features'); 
 
      var newList = carsList.filter(function(item) { 
 
        switch (brand.value) { 
          case 'toyota': 
            return item.brand === 'Toyota'; 
            break; 
          case 'audi': 
            return item.brand === 'Audi'; 
            break; 
          case 'ford': 
            return item.brand === 'Ford'; 
            break; 
          case 'volkswagen': 
            return item.brand === 'Volkswagen'; 
            break; 
          case 'bmw': 
            return item.brand === 'BMW'; 
            break; 
          case 'subaru': 
            return item.brand === 'Subaru'; 
            break; 
          case 'any': 
            return item 
        } 
      }). 
 
      filter(function(item) { 
 
        switch (year.value) { 
          case '1': 
            return item.year <= 2000; 
            break; 
          case '2': 
            return item.year <= 2010; 
            break; 
          case '3': 
            return item.year >= 2010; 
            break; 
          case 'any': 
            return item; 
        } 
      }). 
 
      filter(function(item) { 
 
        switch (price.value) { 
          case 'low': 
            return item.price <= 100000; 
            break; 
          case 'middle': 
            return (item.price >= 100000 && item.price <= 500000); 
            break; 
          case 'high': 
            return item.price >= 500000; 
            break; 
          case 'any': 
            return item; 
        } 
      }). 
 
      filter(function(item) { 
 
        switch (owners.value) { 
          case '1': 
            return item.owners === 1; 
            break; 
          case '2': 
            return item.owners === 2; 
            break; 
          case '3': 
            return item.owners >= 3; 
            break; 
          case 'any': 
            return item; 
        } 
      }). 
 
      filter(function(item) { 
        if (features[0].checked) { 
          return item.features.transmission === 'auto'; 
        } else { 
          return item; 
        } 
      }). 
 
      filter(function(item) { 
        if (features[1].checked) { 
          return item.features.ac === true; 
        } else { 
          return item; 
        } 
      }); 
 
 
      console.log(newList); 
      return newList 
    }, 
 
    clearList: function() { 
      var listItem = document.querySelectorAll('.cars-list__item'); 
 
      for (var i = 0; i < listItem.length; i++) { 
        listItem[i].remove(); 
      } 
    }, 
  } 
})(); 
 
var controller = (function(dataCtrl, UICtrl) { 
 
  // 1. Получить массив с исходными данными 
  var carsList = dataCtrl.getData(); 
 
  // 2. Отрисовать исходный список авто 
  UICtrl.dispalyCars(carsList); 
 
  //Выполнить фильтрацию 
  var filterForm = document.querySelector('.filter'); 
 
  var filterFormHandler = function() { 
    // 1. Получить данные отфильтрованного массива 
    var filteredList = UICtrl.filterData(carsList); 
 
    // 2. Очистить старый список 
    UIcontroller.clearList(); 
 
    // 3. Oтрисовать новый список 
    UICtrl.dispalyCars(filteredList); 
  } 
 
  filterForm.addEventListener('change', filterFormHandler); 
 
})(dataController, UIcontroller);
.cars-list { 
  padding: 0; 
  margin: 0; 
  min-height: 360px; 
} 
 
.cars-list__item { 
  background-color: rgba(64, 161, 241, 0.753); 
  box-sizing: border-box; 
  width: 1000px; 
  height: 30px; 
  margin-top: 5px; 
  margin-bottom: 5px; 
  padding-top: 5px; 
  padding-left: 5px; 
  border-radius: 10px; 
  list-style: none; 
} 
 
.filter { 
  background-color: silver; 
  width: 1000px; 
  height: 30px; 
  margin-top: 20px; 
  padding-top: 5px; 
  padding-left: 5px; 
  border-radius: 10px; 
}
<div class="main"> 
  <ul class="cars-list"></ul> 
  <form action="#" class="filter" autocomplete="off"> 
    <select name="barnd" id="brand-type" class="filter__brand"> 
      <option value="any" selected>Любaя марка</option> 
      <option value="toyota">Toyota</option> 
      <option value="audi">Audi</option> 
      <option value="ford">Ford</option> 
      <option value="volkswagen">Volkswagen</option> 
      <option value="bmw">BMW</option> 
      <option value="subaru">Subaru</option> 
    </select> 
 
    <select name="year" id="cars-year" class="filter__year"> 
      <option value="any" selected>Любой год выпуска</option> 
      <option value="1">до 2000 года</option> 
      <option value="2">до 2010 года</option> 
      <option value="3">после 2010 года</option> 
    </select> 
 
    <select name="price" id="cars-price" class="filter__price"> 
      <option value="any" selected>Любая цена</option> 
      <option value="low">до 100000&#x20bd;</option> 
      <option value="middle">100000 - 500000&#x20bd;</option> 
      <option value="high">от 500000&#x20bd;</option> 
    </select> 
 
    <select name="owners" id="cars-owners" class="filter__owners"> 
      <option value="any" selected>Любое число собственников</option> 
      <option value="1">Один</option> 
      <option value="2">Два</option> 
      <option value="3">Три и более</option> 
    </select> 
 
    <input type="checkbox" name="features" value="auto" id="transmisson"> 
    <label class="feature feature--auto" for="transmisson">Автоматическая коробка передач</label> 
 
    <input type="checkbox" name="features" value="yes" id="conditioner"> 
    <label class="feature feature--conditioner" for="conditioner">Кондиционер</label> 
  </form> 
</div>

READ ALSO
Как осуществляется проверка в Vue?

Как осуществляется проверка в Vue?

Разрабатываю приложение на laravel+vue, и возникло пару вопросов:

136
Ошибка в PhantomJS

Ошибка в PhantomJS

Вот что я пишу, и что выводит

195
Непонятный NaN в js [дубликат]

Непонятный NaN в js [дубликат]

На данный вопрос уже ответили:

170
Как лучше реализовать модуль в js?

Как лучше реализовать модуль в js?

Задумался вот о чём: на сайтах по js написано, что лучше всего реализовывать модуль через такой приём:

151