Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #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 фильтров всё бы раз и заработало, без необходимости переписывать кучу кода. Может через строку как-то попробовать, не знаю...

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

Пардон за сумбур в голове и плохое знание матчасти, но знал бы не спрашивал.
Ответить с цитированием
  #2 (permalink)  
Старый 13.06.2015, 11:09
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,068

функция фильтрации массива , любым количеством фильтров

фильтрация массива
function blender(arr, filters) {
    return arr.filter(function(el) {
        return filters.every(function(filter) {
            return filter(el)
        })
    })
};
var projects = [
    {
        id: 'pb-15001',
        name: 'ПБ-15.001',
        area: 200,
        thumbUrl: 'img/projects/p-15001/p15001-thumb.jpg',
        floors: 400,
        type: 'индивидуальный',
        bedrooms: 4
    },
    {
        id: 'pb-15001',
        name: 'ПБ-15.001',
        area: 300,
        thumbUrl: 'img/projects/p-15001/p15001-thumb.jpg',
        floors: 200,
        type: 'индивидуальный',
        bedrooms: 4
    },
    {
        id: 'pb-15002',
        name: 'ПБ-15.001',
        area: 200,
        thumbUrl: 'img/projects/p-15001/p15001-thumb.jpg',
        floors: 100,
        type: 'индивидуальный',
        bedrooms: 4
    }
]

fn = function(el) {
  return el['floors'] == 100
}
fn2 = function(el) {
  return el['area'] == 200
}
var test = blender(projects, [fn, fn2])
alert(JSON.stringify(test))

Последний раз редактировалось рони, 13.06.2015 в 11:11.
Ответить с цитированием
  #3 (permalink)  
Старый 13.06.2015, 11:34
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

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

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

рони,
Спасибо за пример. Изучу.

laimas,
Сообщение от laimas Посмотреть сообщение
Если это фильтр для имеющего на странице, то под JQ есть плагин, который фильтрует по указанным свойствам, сортирует, может скрывать тем, что не указаны в фильтрах, и др. Название не помню его, но найти можно, да и не один скорее всего.
Да, дело касается именно фильтрации имеющегося на странице, по-возможности без удаления_старого_каталога / создания_нового /выводе_нового. В идеале просто перебрать контейнеры после каждого вызова соответствующей функции и отобразить/скрыть.

Плагины использовать сейчас не хочу, т.к. по сути именно и изучаю как они внутри работают.
Ответить с цитированием
  #5 (permalink)  
Старый 13.06.2015, 13:53
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

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

Меня смущает тип данных filter-by-house-type, filter-by-bedrooms, ... то есть речь о скорее всего идет о недвижимости. Я как раз сейчас работаю над заказом для агентства недвижимости. У них два десятка риэлторов, и каждый вынужден получать табличные данные такими, какие установлены в единой конфигурации. Для администрирования это крайне неудобно, а тасовать полученные данные на клиенте используя фильтрацию, это бессмыслица, так сервер вынужден отдавать все скопом, а не только то, что нужно, а если предполагается и редактирование табличных данных, то это усложнение как серверной, так клиентской части кода. Да и вывод табличных данных для администрирования не ради тасовать на клиенте делается, а все тики для работы.

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

Фильтр, а также и наборы для других представлений, как то сортировка, и т.д., уж никак не определяются как filter-by-house-type, filter-by-bedrooms. Поступая таким образом практически не возможно написать универсальное управление выводом, для которого выходными данными были бы только таблица и ее поля. Для каждой таблицы и ее полей придется писать свою "кочергу".

Агентство занимается недвижимостью - квартиры, дома, участки, и другие. Все это, это хранение данных в различных таблицах. Но не смотря на это, и различие в типах недвижимости, у этих таблиц много полей описывающих один и те же данные: адреса, площади, количество комнат и т.п. Кроме этого ведь есть и другие таблицы обслуживающие работу агентства и тоже нуждающиеся в управлении.

Фильтр, вернее параметры фильтра, как и параметры сортировки определяются типом полей данных. А их не так и много, числа, числа с плавающей точкой, списки, даты. Достаточно унифицировать имена полей таблиц так, чтобы чтобы к примеру поле адреса "город" во всех таблицах указывало на на один и тот же тип параметров, который будет выбраться как параметры фильтра или сортировки.

Остается в таблицу определяющую поля таблиц, которым разрешают/запрещают выбор для какого либо из наборов (отображение, фильтр, сортировка и т.д.), указать тип данных, по которым клиент и будет строить поля для выбора параметров фильтра, сортировки...

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

А вот для пользователей на страницах, которым тоже будет доступен фильтр вывода данных, определяется иной сервис. Фильтр, это все таки не тасовать полученный набор на странице, а получение данных только отвечающих фильтру. Но так как вывод данных в любом случае будет постраничный, а на каждой из них пользователя может что-то заинтересовать, то удобно было бы делать выборку таких объектов на каждой странице и заносить их в набор. В этом случае можно запрашивать у сервера только те данные, которые заинтересовали пользователя, и с ними уже проводить различные операции - сортировать, удалять из набора и т.д..

Я это делал исходя из задач, которые определяются риэлтором для работы с данными, и сервисом для клиента. Какова конечная задача вашего фильтра я не знаю, если ради "крутить/вертеть" данными на странице, ну красиво, но а толку от этого? Для галереи, и подобного контента это и хорошо, да и полезно будет, а если недвижимость, то вряд ли целесообразно.
Ответить с цитированием
  #6 (permalink)  
Старый 14.06.2015, 13:07
Аватар для armidoll
Кандидат Javascript-наук
Отправить личное сообщение для armidoll Посмотреть профиль Найти все сообщения от armidoll
 
Регистрация: 28.05.2015
Сообщений: 116

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

То что будет реализовано в данной версии, это, я бы сказал, не какое-то серьезное решение с БД, а скорее ближе к вашему понятию "крутить-вертеть" только на клиентской стороне. Там проектов-то не более сотни будет в лучшем случае, да и то в будущем.
Ответить с цитированием
  #7 (permalink)  
Старый 14.06.2015, 15:18
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

Ну если такое, может быть это и имеет смысл, хотя на мой взгляд, это бессмыслица, даже пусть и для сотни объектов. Пользователь то ведь использует фильтр в надежде на то, что сервер вернет ему объекты удовлетворяющие условию фильтра, для этого они и служат, и не только для недвижимости, но и для вывода товаров и прочего.
А тут получается, что сперва вывалили все, а потом в этом "мусоре крутить-вертеть" надо.
И где в этом смысл зарыт я не понимаю.
Ответить с цитированием
  #8 (permalink)  
Старый 14.06.2015, 18:55
Аватар для armidoll
Кандидат Javascript-наук
Отправить личное сообщение для armidoll Посмотреть профиль Найти все сообщения от armidoll
 
Регистрация: 28.05.2015
Сообщений: 116

Так а если объектов немного (<100), они не связаны с другими таблицами/полями/не являются сложными структурами, жрущими вагон ресурсов, то зачем каждый раз после изменения фильтров к серверу обращаться?

И такой еще момент, вываливается не все, а только определенная достаточно однородная категория, мы ведь не валим в кучу проекты домов, одежду и электробритвы.

С кэшем ведь удобнее и быстрее будет в итоге, разве нет? Вот представьте паршивый бесплатный wi-fi в ресторанном дворике где-нить или на даче.

К примеру, как вы считаете, каталоги такого уровня стоит пользователю целиком пересылать и дальше фильтровать только у него или после каждого изменения фильтров с запросами к серверу обращаться (я ведь правильно понимаю идею?):
http://doma-is-brusa.com/catalog/
или
http://www.rovaniemi.ru/houses/houses/individual/large/

PS Обратите внимание, это не БД по недвижке, тут совсем другой масштаб, он гораздо скромнее.
Ответить с цитированием
  #9 (permalink)  
Старый 14.06.2015, 20:20
Профессор
Отправить личное сообщение для laimas Посмотреть профиль Найти все сообщения от laimas
 
Регистрация: 14.01.2015
Сообщений: 12,990

Сообщение от armidoll
не являются сложными структурами, жрущими вагон ресурсов
Это кто такое сказал, что сложная структура, это жрать ресурсы вагонами? )

Сообщение от armidoll
С кэшем ведь удобнее и быстрее будет в итоге, разве нет?
Кеширование не является способностью исключительно клиента, кешировать можно даже и запросы, но суть не в этом. Тем более, пусть у меня "паршивый бесплатный wi-fi в ресторанном дворике где-нить или на даче". Захожу я к вам с "паршивого", а вы "ведь не валите в кучу проекты домов, одежду и электробритвы", а значит, по идее, я буду иметь представление о том, что же вы "валите" на страницу. Но каким образом я получу это представление: а) попадая на главную страницу, где знакомлюсь с родом деятельности сервиса, и загружаю на свой "паршивый" минимально необходимый для этого объем информации; б) а не тут то было, мне на мой "паршивый" вывалили все дома или еще чего-то?

Надеюсь, что вариант а). Возникает вопрос - если я заинтересован в покупке, и возможно у вас есть дом с видом на Эйфелеву башню, с двумя этажами и о трех окнах, с ценой от и до, то что для моего "паршивого" будет выгоднее: а) если есть выбор по фильтру, выбрать нужные мне параметры его, и получить пусть уже больший, чем у главной страницы объем, но все таки ограниченный; б) нет, получай все сполна, а потом ищи в нем свою башню?

Будь у меня "паршивый", я тем более бы предпочел вариант а). То что клиент к вам зашел, еще не означает, что он что-то выберет, и совсем не обязательно клиенту впаривать все, ссылаясь на "прожорливость ресурсов или паршивость устройств". Решать за клиента что ему надо, это на мой взгляд самоуверенность, а вот предугадать желания клиента, это хорошо. И если бы я такое решал в рамках ограниченного предложения, то использовал бы, например, таргетинг, с целью предугадать и предложить, если есть что. Но в любом случае бы старался избежать вываливания всего что есть клиенту.

Я не пытаюсь вас отговорить, делайте как считаете нужным, любая идея имеет право на осуществление, а успешна ли она будет, время покажет. Это всего лишь мое представление.

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

Спасибо, что тратите на меня свое время, на разъяснения. Честно, благодарен!

Когда дочитаю учебник по javascript и возьму в руки, например, по php, встану на диаметрально противоположную позицию по отношению к решаемой задаче и негативному анализу будет подвергнут javascript.

Через анализ к синтезу

PS Вы мне про высокие материи широкого контекста, а я только с массивами/объектами сижу разбираюсь

Последний раз редактировалось armidoll, 14.06.2015 в 21:49.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск