Показать сообщение отдельно
  #1 (permalink)  
Старый 13.06.2015, 10:42
Аватар для armidoll
Кандидат Javascript-наук
Отправить личное сообщение для armidoll Посмотреть профиль Найти все сообщения от armidoll
 
Регистрация: 28.05.2015
Сообщений: 116

Каталог с несколькими фильтрами: проверка на отображение (в т.ч. используется jQuery)
Доброго времени суток.

Задача: сделать каталог с фильтрами

Сам вопрос/суть проблемы в п.6. в самом конце

Принятые проектные решения:

1. Элементы каталога первоначально содержатся в виде (возможно количество свойств увеличится):
var projects = [
    {
        id: 'pb-15001',
        name: 'ПБ-15.001',
        area: 200,
        thumbUrl: 'img/projects/p-15001/p15001-thumb.jpg',
        floors: 2,
        type: 'индивидуальный',
        bedrooms: 4
    },
    {
        ...
    },
    {
        ...
    }
]


2. Функция makeCatalog() создает HTML код (добавляет в DOM другая) только при инициализации. В итоге контейнером для отдельного элемента каталога служит <div />. Эта же функция заполняет массив refers[] содержащий связанные ссылки на элементы в projects[] (см. п.1) и соответствующие контейнеры <div />.

!!! Также сюда хочу запихнуть информацию ( см. hiddenBy{} ), какие фильтры потребовали скрыть контейнер <div />, чтобы отображался только в том случае, если этому не препятствует ни один из фильтров. Не факт, что такое направление моих мыслей правильное.

function makeCatalog(){ // Create HTML part of the catalog and fill cross-ref array
projects.forEach(function(project){
            var $div = $('<div id="' + project.id + '"></div>'),
                $a = $('<a href="#"></a>');
            $a.append( $('<img src="' + project.thumbUrl + '"/>') );
            $a.append( $('<p><span>' + project.name + '</span><span>' + project.area + ' м<sup>2</sup></span></p>') );
            $div.append($a);
            refers.push({
                project: project,
                $element: $div,
                hiddenBy: {}

            });
        });
    }


3. Есть несколько фильтров (их HTML часть):
<aside id="filters">
                <div id="filter-by-area">
                    Площадь<br />
                    Min
                    <input id="area-min" name="area-min" type="number" />
                    Max
                    <input id="area-max" name="area-max" type="number" />
                    <div id="filter-slider"></div>
                </div>
                <div id="filter-by-order">
                    Сортировка по<br />
                    <input type="radio" name="sort-order" value="by-name" checked="checked" />новизне<br />
                    <input type="radio" name="sort-order" value="area-asc" />возрастанию<br />
                    <input type="radio" name="sort-order" value="area-desc" />убыванию
                </div>
                <div id="filter-by-house-type">
                    Тип дома<br />
                    <input type="checkbox" checked="checked" name="floors1" />Одноэтажные<br />
                    <input type="checkbox" checked="checked" name="floors2" />Двухэтажные
                </div>
                <div id="filter-by-project-type">
                    Тип проекта<br />
                    <input type="checkbox" checked="checked" name="individual" />Индивидуальные<br />
                    <input type="checkbox" checked="checked" name="typical" />Типовые
                </div>
                <div id="filter-by-bedrooms">
                    Кол-во спален<br>
                    <input type="checkbox" checked="checked" name="bed1" />1
                    <input type="checkbox" checked="checked" name="bed2" />2
                    <input type="checkbox" checked="checked" name="bed3" />3
                    <input type="checkbox" checked="checked" name="bed4" />4
                    <input type="checkbox" checked="checked" name="bed5" />5
                </div>
            </aside>


4. При наступлении события запускаем различные функции (они пока не прописаны толком) в зависимости от инициировавшего фильтра:
$('#filters').children().change( function(e) {

            console.log('fired: ' + $(this).attr('id'));

            var firedFilterId = $(this).attr('id');
            var firedFilterEl = e.target;

            switch (firedFilterId){

                case 'filter-by-area':
                    console.log('switched to: filter-by-area');
                    updateRefersByArea( $minArea.val(), $maxArea.val(), firedFilterId );
                    break;

                case 'filter-by-order':
                    console.log('switched to: filter-by-order');
                    sortRefersByArea(firedFilterEl.value);
                    appendCatalog();
                    break;

                case 'filter-by-house-type':
                    console.log('switched to: filter-by-house-type');
                    console.log(firedFilterEl.name);
                    break;

                case 'filter-by-project-type':
                    console.log('switched to: filter-by-project-type');
                    console.log(firedFilterEl.name);
                    break;

                case 'filter-by-bedrooms':
                    console.log('switched to: filter-by-bedrooms');
                    console.log(firedFilterEl.name);
                    break;

                default:
                    break;

             }
        });


5. Например, функция updateRefersByArea() отображает или скрывает контейнеры <div /> в зависимости от выбранного значения площади:
function updateRefersByArea(minArea, maxArea, firedId){ // Show or hide projects depending on change of min and max area values

        console.log('updateRefersByArea() is starting...');

        refers.forEach(function(record){

            var hidden = record.hiddenBy;

            if (hidden.firedId == null){
                hidden.firedId = false;
            }

            if (record.project.area >= minArea && record.project.area <= maxArea ){

                hidden.firedId = false;
                record.$element.show()
                
            } else {

                hidden.firedId = true;
                record.$element.hide();
            }
        });
    }


6. Теперь, наконец-то, вопрос:

Каким образом лучше сделать проверку в каждой из функций, запускающейся в зависимости от того, какой фильтр выстрелил (см., например, п.5)?
В результате проверки функция должна отобразить/не отобразить соответствующий контейнер <div /> в зависимости от того, потребовали или нет еще какие-то фильтры скрыть контейнер <div />.

Вижу два очевидных пути:
1. Перебирать по именам значения в hiddenBy {} на true / false
2. Преобразовать hiddenBy {} в массив hiddenBy[] и каждую функцию/фильтр закрепить за элементом массива с определенным индексом

Не хочу так поступать, т.к. п.3 покоя не даёт

3. В голове крутится, что неплохо бы было как-то сделать, чтобы куда-то в "список" добавлялся в нашем случае firedFilterId (например, в массив), и дальше происходило следующее при запуске функции на отображение/скрытие:
3.1. Удаляется/добавляется в список firedFilterId
3.2. Проверяется length массива, если '0' отображаем сразу без проблем (т.к. не содержит id ни одного фильтра), иначе пропускаем / или смотрим есть ли такое св-во у объекта

Сегодня сяду долбить вариант с массивом, потом хочу попробовать через свойства объектов. Суть наверное ясна, не хочется прописывать все условия поштучно или завязывать функции/фильтры на элементы массива вручную, а хочется чего-то такого, чтобы если потом добавишь еще хоть 10 фильтров всё бы раз и заработало, без необходимости переписывать кучу кода. Может через строку как-то попробовать, не знаю...

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

Пардон за сумбур в голове и плохое знание матчасти, но знал бы не спрашивал.
Ответить с цитированием