Недавно на Хабре проскочила статья об активных фильтрах на сайтах. И вот что меня удивило — многие в комментариях интересовались а как же сего зверя реализовать самостоятельно. Вот я и постараюсь доступно и по шагам разложить основные положения реализации данной фичи на сайте.
Сторона клиента
Больше всего кода прийдется написать именно тут. Хотя все зависит от сложности выборки на стороне сервера. Если воспользоваться готовым поисковым механизмом типа Sphinx, то писать прийдется крайне мало, а вот на клиенте, как я говорил, прийдется попотеть.
Итак, представим что у нас вполне конкретная задача: фильтровать фильмы по неким параметрам. Для нашего примера ограничимся жанром и полем сортировки записей (по году выпуска или по рейтингу).

классы участники и отношения между ними в разрабатываемой системе
Графический интерфейс тоже усложнять не станем. В столбик сделаем группу чекбоксов и селект для выбора сортировки, под ними список отфильтрованых результатов.
Теперь можно нахардкодить много кода, который проверяет каждый элемент, читает какие-то его атрибуты, создает строку запроса на сервер и отправляет все для получения данных, но мы поступим иначе: сначала мы создадим два класса, которые будут представлять сущность каждого типа выбора. Чекбоксами мы можем выбрать несколько значений для отображения, а селектом только одно. Таким образом нам нужны классы MultipleSelect и SingleSelect. Их интерфейс на диаграмме.

Модели еденичного и множественного выборов
Как видно из диаграммы, интерфейсы классов идентичные. Они оба обладают методами select(), getSelected() и reset(). Отличия, как принято в ООП, наблюдаются только в реализации. Класс SingleSelect в методе select() заполняет указанным значением приватную переменную selected, и таким образом у него выбран всегда только один конкретный вариант, который возвращается методом getSelected().
MultipleSelect же в свою очередь при каждом вызове select() добавляет переданный идентификатор во внутренний массив selected, и метод getSelected() возвращает этот массив. Дополнительный метод unselect(), как можно догадаться, удаляет из массива выбранных значений указанное.
Методы reset() в обоих случаях ведут себя одинаково — они очищают приватную переменную от установленных значений.
Теперь у нас есть рабочая модель пользовательского выбора и мы можем связать ее с интерфейсом.
// создаем объект выбора для жанров var genres_selector = new MultipleSelect(); /** * для каждого чекбокса в списке жанров добавляем событие на нажатие, * которое отмечает выбранный жанр в объекте выбранных, либо удаляет его от туда */ $$( 'ul.genres input[type=checkbox]' ).each( function ( cb_element ) { cb_element.addEvent( 'click', function () { if ( this.checked ) { genres_selector.select( this.get( 'value' ) ); } else { genres_selector.unselect( this.get( 'value' ) ); } } ); } ); // создаем объект выбора для сортировки var sort_selector = new SingleSelect(); // отмечаем выбор, при изменении значения в селекте $( 'sort-selector-el' ).addEvent( 'change', function () { sort_selector.select( this.get( 'value' ) ); } );
Теперь при взаимодействии с пользовательским интерфейсом наша модель заполняется данными.
Последнее что необходимо делать — отправлять запросы для обновление коллекций на сервер. Чтобы не зависеть от кол-ва критериев фильтрации, а также инкапсулировать логику в одном месте, создадим еще один класс «FilterRequestor».

Класс для получения с сервера отфильтрованных данных
Какой принцип действия у этого класса?
После инстанциирования он заполняется объектами фильтра, каждому из которых присваивается название атрибута (второй параметр в методе addSelector() ). При добавлении нового селектора, ему при помощи шаблона «Наблюдатель«, добавляем слушателя на события onSelect, onUnselect и onReset, которые бросаются при каждом вызове методов select(), unselect() и reset() соответственно.
При каждом из этих действий FilterRequestor должен запросить данные с сервера. Для этого он использует метод doRequest(), по окончании работы который бросает событие onSuccess, передав данные как аргумент функции-слушателю.

Все. Осталось получить массив отфильтрованых данных (либо готовый HTML) и вставить на место старого.
О серверной части говорить пока не стану — там все должно быть понятно. Ну а если нет — пишите и эту тему раскрою более детально.
А еще можно использовать обычную форму, какой-нибудь jQuery Form Plugin, загружать аяксом кусок страницы с результатами и делать $(‘.results-div’).html(response).
к сожалению работать этот вариант будет только при стандартном наборе контролов. Как только дизайнер введет новые элементы управления — компонент jQuery перестанет работать
Тема сисек не раскрыта =(
Ты когда включаешь множественный выбор фильтров — как-то помечай какие фильтры выбраны. Я тебе скриншот отсылал.
не понимаю о чем ты
спасибо за статью.
не понятно присутствие классов Film и Genre. Не могли объяснить этот момент?
и, конечно же, хотелось бы увидеть вашу реализацию серверной части.
пропуситил «бы».
Не могли бы объяснить этот момент?