Фильтр по чекбоксам

140
08 марта 2022, 00:20

Я пытаюсь отсортировать данные с джсона по чекбоксам. Пример данных:

 [{
    "id": 111,
    "name": "Standart Room",
    "img": "rooms_img_1.jpg",
    "price": 126,
    "category": "single",
    "roomType": "room",
    "adults": 1,
    "children": 0,
    "bed": "King",
    "facilities": "Closet with hangers, HD flat-screen TV, Telephone",
    "area": 20,
    "breakfast": false,            
    "reservedFrom": "2020-02-07T23:28:56.782Z",
    "reservedTo": "2020-02-09T23:28:56.782Z"      
},{   
    "id": 112,
    "name": "Standart Room",
    "img": "rooms_img_1.jpg",
    "price": 126,
    "category": "single",
    "roomType": "room",
    "adults": 1,
    "children": 0,
    "bed": "King",
    "facilities": "Closet with hangers, HD flat-screen TV, Telephone",
    "area": 20,
    "breakfast": false,
    "reservedFrom": "2020-02-01T23:28:56.782Z",
    "reservedTo": "2020-02-05T23:28:56.782Z"
},  {
    "id": 313,
    "name": "Double Room",
    "img": "rooms_img_3.jpg",
    "price": 320,
    "category": "double",
    "roomType": "room",
    "adults": 2,
    "children": 1,
    "bed": "Twin",
    "facilities": "Closet with hangers, HD flat-screen TV, Telephone",
    "area": 20,
    "breakfast": false,
    "reservedFrom": "2020-03-07T23:28:56.782Z",
    "reservedTo": "2020-03-091T23:28:56.782Z"       
},   {
    "id": 314,
    "name": "Double Room",
    "img": "rooms_img_4.jpg",
    "price": 320,
    "category": "double",
    "roomType": "room",
    "adults": 2,
    "children": 0,
    "bed": "Twin",
    "facilities": "Closet with hangers, HD flat-screen TV, Telephone",
    "area": 20,
    "breakfast": false,
    "reservedFrom": "2020-03-07T23:28:56.782Z",
    "reservedTo": "2020-03-091T23:28:56.782Z"       
}]

после чего фильтрую его по кол-ву людей и датам и загоняю их в новый массив availbleRooms.

  availableRooms = data.filter(room => {
            let reservedFromData = new Date(room.reservedFrom);
            let reservedToData = new Date(room.reservedTo);
            let checkinDate2 = new Date(checkinDate);
            let checkoutDate2 = new Date(checkoutDate);
            let wasNotSet = (room.reservedFrom == undefined || room.reservedTo == undefined);
            let isAvaliable =  wasNotSet || ((checkinDate2 <= reservedFromData || checkinDate2 >= reservedToData) && (checkoutDate2 <= reservedFromData || checkoutDate2 >= reservedToData));
            if(!room.adults >= adultsValue && room.children >= childrenValue && isAvaliable)
            return false;
            if(isBreakfastRequired && !room.breakfast)
                return false;
            if(suiteType == true && room.roomType != "suite" ||
              roomType == true  && room.roomType != "room"  ||
              suitesAndRooms == true && room.roomType != "suite" && room.roomType != "room")
                return false;
            if(room.bed == "King" && !kingBed ||
              room.bed == "Queen" && !queenBed ||
              room.bed == "Twin" && !twinBed && 
              (kingBed || queenBed || twinBed))
                return false;
            return true;
              });      

Такая фильтрация показывает только первый найденный эл, если условие показать и тип кровати кинг и квин, выведет только первый тип.
Как исправить мой фильтр?
И может кто-то подскажет варианты как сделать его изящнее и не таким полотном. Спасибо

Answer 1

Пара предварительных советов по организации кода:

Для начала можно forEach заменить на filter:

let availableRooms = data.filter(room => {
    let reservedFromData = new Date(room.reservedFrom);
    let reservedToData = new Date(room.reservedTo);
    let checkinDate2 = new Date(checkinDate);
    let checkoutDate2 = new Date(checkoutDate);
    let wasNotSet = (room.reservedFrom == undefined || room.reservedTo == undefined);
    let isAvaliable =  wasNotSet || ((checkinDate2 <= reservedFromData || checkinDate2 >= reservedToData) && (checkoutDate2 <= reservedFromData || checkoutDate2 >= reservedToData));
    return room.adults >= adultsValue && room.children >= childrenValue && isAvaliable;
});

Далее, можно туда же засунуть все остальные условия фильтрации, а не проходить массив целую кучу раз (что заметный проигрыш в производительности, если комнат много):

let availableRooms = data.filter(room => ({
    let reservedFromData = new Date(room.reservedFrom);
    let reservedToData = new Date(room.reservedTo);
    let checkinDate2 = new Date(checkinDate);
    let checkoutDate2 = new Date(checkoutDate);
    let wasNotSet = (room.reservedFrom == undefined || room.reservedTo == undefined);
    let isAvaliable =  wasNotSet || ((checkinDate2 <= reservedFromData || checkinDate2 >= reservedToData) && (checkoutDate2 <= reservedFromData || checkoutDate2 >= reservedToData));
    if(!room.adults >= adultsValue && room.children >= childrenValue && isAvaliable)
        return false;
    // обратите внимание, эта строчка плохо читается из-за неудачного названия переменной hasBreakfast - лучше бы она называлась isBreakfastRequired
    if(hasBreakfast && !room.breakfast)
        return false;
    ... // остальные условия в том же порядке
}));

Что касается собственно логики фильтрации, тут у вас довольно явная ошибка: вы вначале при kingBed == true оставляете в avaliableRooms комнаты, у которых тип кровати King, а затем среди них в случае queenBed == true ищете комнаты с Queen, а это, очевидно, пустое множество. Давайте попробуем аккуратно дописать оставшиеся условия (по большому счёту, вы забыли else в тех условиях + в фрагментах типа room.bed == "King" && room.bed == "Twin" на самом деле должно быть "или" – иначе условие не выполнится никогда):

    if(!room.adults >= adultsValue && room.children >= childrenValue && isAvaliable)
        return false;
    if(hasBreakfast && !room.breakfast)
        return false;
    if(suiteType == true && room.roomType != "suite" ||
       roomType == true  && room.roomType != "room"  ||
       suitesAndRooms == true && room.roomType != "suite" && room.roomType != "room")
        return false;
    if(kingBed == true && room.bed != "King" ||
       queenBed == true && room.bed != "Queen" ||
       twinBed == true && room.bed != "Twin" ||
       kingBed == true && twinBed == true && (room.bed == "King" || room.bed == "Twin") ||
       ...
       )
        return false;
    return true;
}));

Но, конечно, это всё равно ужасная реализация, короче будет описать логику "если тип кровати не соответствует фильтру", т.е.:

    if(room.bed == "King" && !kingBed ||
       room.bed == "Queen" && !queenBed ||
       room.bed == "Twin" && !twinBed)
       // еще, возможно, понадобится взять всё в скобки и добавить && (kingBed || queenBed || twinBed)
       // если нужна логика "ничего не отмечено = всё выбрано"
        return false;

а ещё лучше было бы не хранить данные о каждом типе отдельным флагом (kingBed, queenBed, twinBed), а в объекте с теми же полями (selectedBedTypes: { King: boolean, Queen: boolean, Twin: boolean }) и обходить его в for .. in .. цикле – иначе добавление нового типа кровати заставит вас менять кучу кода.

READ ALSO
Вывести случайное кол-во div из списка

Вывести случайное кол-во div из списка

В файле есть n количество div с классом item-1, item-2,

81
Разница между методами arr.map() и arr.filter()

Разница между методами arr.map() и arr.filter()

Поясните разницу между выводом одного и того же кода методами arrfilter() и arr

238
Как в fancybox добавить галерею с picture?

Как в fancybox добавить галерею с picture?

вот код но надо не картинку ,а picture

77