Pull to refresh

CatalogBox — идея развития ComboBox'а

Reading time10 min
Views5.2K
Программист должен упрощать жизнь пользователю, а не себе.
(конечно, есть нюансы)

Автор статьи

Был ComboBox


Статья описывает идею визуального веб-контрола для выбора элемента из списка. Эта идея о том, как можно эволюционировать ComboBox (он же DropDown, он же select в html) для повышения удобства программного продукта для пользователя – чтобы контрол выбора стал намного удобнее и дружелюбнее при выборе сложных объектов из больших и не очень списков. Ведь задача программиста — в непрерывном улучшении и упрощении жизни пользователя.

Это идея, реализация которой есть только частичная и только для ASP.NET Web Forms в связке с devexpress – поскольку у меня большой бекграунд именно на этой связке технологий.

Эта статья не для тех, кто хочет скопипастить код, нажать F5 и увидеть результат. Ее корректнее всего было бы отнести к документам, которые называют Функциональными Требованиями или даже Функциональным Дизайном. Поэтому, если вам интересен взгляд на эволюцию удобства, то, надеюсь, статья будет полезна.

Эволюция ComboBox’а – что уже есть


Сначала приведу список удобных фич, которые уже есть в хороших реализациях визуальных контролов. В этом параграфе нет ничего нового, только описание функциональности, уже реализованной в передовых библиотеках визуальных контролов.

Например, у devexpress фичи относительно select в html такие (в порядке, на мой взгляд, уменьшения необходимости, то есть сначала самое важное):

  • Фильтр по введенной строке:



    По мере введения символов в контрол список фильтруется. Тут замечания:

    По каким полям проверять вхождение введенной строки? Если проверять по тем, которые в контроле не отображаются, то пользователю может быть неочевидно поведение. Но иногда такое может требоваться. А если пользователь вводит строку, содержащую в себе границу при конкатенации полей? То есть, если выводится ФИО сотрудника, скажем, «Черняев Константин», а имя и фамилия хранятся в разных полях данных, и пользователь вводит «яев конс» (здесь и далее регистр символов не имеет значения – считаю, что при поиске текста это стандарт де-факто). Дружелюбно со стороны контрола было бы найти эту запись:



    — Обычно сортировку делают по алфавиту. И когда пользователь вводит строку (скажем, «стол»), и такой элемент в списке есть, причем есть и такие элементы, которые эту строчку содержат, но не равны ей («столб», «апостол», «пистолет»), то получится, что пользователю приходится листать список, выбирая нужный (а порядок в этом примере будет такой: «апостол», «пистолет», «стол», «столб»). Причем уточнить запрос и сузить список невозможно. Если список большой, это большой минус к дружественности.
    Решением этой проблемы будет сортировка по признаку «равенство/вхождение». То есть первыми должны идти записи, равные введенной строке, а потом остальные. Я бы даже пошел дальше – сначала равные, потом начинающиеся с этой строки, потом остальные.
  • Автодополнение, автовыбор первого из найденных:



    По мере набора текста контрол фильтрует данные, показывает их, и дополняет вводимый текст
    первым из найденных. При потере фокуса будет выбран он же.
    Замечание – если пользователь вводит символы не с начала нужной ему строки, автовыбрать ее ему не удастся.
  • Можно включить режим, когда можно написать новое значение, которого нет в списке. Иначе – нельзя ввести текст, по которому не найдено ни одного элемента. Как бы режим подсказок, когда ввести можно не только то, что подсказывают.
    Такой режим упрощает жизнь пользователя, когда у него должна быть возможность добавления нового значения, которое не является сложным объектом – просто строчка. Например, имя. Или должность на предыдущем месте работы – она может быть любая, но есть список уже известных должностей.
  • Источником данных, то есть самим списком может быть как javascript-массив на клиенте (то есть уже скачанные данные), так и ajax-запрос на сервер (то есть когда клиент скачивает данные ровно по запросу).
  • Virtual scrolling – скролл списка без скачивания всех данных. Продолжение предыдущего пункта. Если данных очень много, то скачиваются только видимые элементы или с небольшим запасом, а при прокрутке списка подкачиваются нужные.
    Если элементов в списке много, то не стоит их все хранить на клиенте – пусть подтягиваются по мере необходимости. А если мало, то можно заранее, при загрузке страницы, их скачать, и хранить в памяти браузера. Сколько мало, а сколько много — сказать загодя нельзя, нужен оптимизационный баланс при сравнении «скачать сразу все данные» vs «при прокрутке видимого окна данных скачивать следующую страницу».
  • Есть возможность запрограммировать кнопки в контроле, например, «сбросить значение», «следующий/предыдущий элемент». Или любое другое нужное пользователю действие. Пример добавления кастомных кнопок:



    В комбике на скриншоте убрана обычная кнопка-треугольник



    , но добавлено три пользовательских.
  • Табличный вид списка:
    Можно структурировать показываемые данные и отображать не только название элемента, но несколько его полей.


  • Стили для ячеек при табличном виде, иконки, шаблоны элемента:




  • Можно еще упомянуть возможность выбора в виде ComboBox’а элемента из иерархического списка, но это другой контрол (DropDownEdit, хотя заголовок у него Tree List Lookup).

Эволюция ComboBox’а — новое


Пользуясь перечисленными возможностями, я постепенно приходил к тому, что не хватает дальнейшей эволюции ComboBox’а:

  1. Легкое добавление кнопки «Сбросить значение». Без программирования.
    Такая кнопка нужна весьма часто, поэтому удобно, когда она добавляется присвоением простому boolean-свойству контрола:

    <comboBox showResetButton=”true” />


  2. Показать, что выбранное значение было изменено.
    Практически любой текстовый редактор показывает, что файл был изменен и не сохранен. Такая возможность кажется удобной и на контролах редактирования. Это касается, конечно, не только ComboBox’а, а вообще всех эдиторов.



    Возможно, стоит добавить возможность откатить изменение в контроле редактирования. Как бы cntr+z.
  3. Ссылка на страницу выбранного элемента. Если, конечно, у сущности элементов списка есть своя страница.

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

    Самым удобным кажется рядом с визуальным контролом написать обычный тег

    <a href='entity?id=...'>i</a>

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

    .

    Пример реализации этих трех пунктов:



    Звездочка означает, что значение было изменено (можно ее показывать как в caption, так и справа от контрола, это дело стиля конкретного проекта – обычно ведь звездочка означает, что значение обязательно для выбора), красный крестик – кнопка «Сбросить значение», i – ссылка на карточку выбранного филиала, кнопка с троеточием – для пункта 4.
  4. При наличии у сущности страницы-каталога с возможностями различных фильтров, удобной визуализации, пейджинга, сортировки etc – выбор сделать с помощью этой страницы-каталога. Это кардинальное улучшение делает ComboBox CatalogBox’ом – ComboBox’ом XXI века.

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

    А для пользователя будет удобно каталог открывать в модальном окошке при нажатии на специальную кнопочку на CatalogBox’е (кнопка-троеточие

    ).

    Пример страницы-каталога:



    На скриншоте каталог открыт в модальном окошке после нажатия на кнопку-троеточие.
    Но сама страница каталога не должна быть привязана к модальности – ее должно быть можно открывать как отдельно и независимо, так и в модальном окне. В модальном окне у грида должна появляться возможность выделить одну выбранную строку (или несколько), после чего становится активной кнопка «Выбрать» (на скриншоте она disabled, потому что выбор не сделан). При ее нажатии выбранное значение подставляется в ComboBox, то есть теперь CatalogBox.
  5. Иногда требуется делать выбор нескольких элементов из списка. Как бы CheckBoxList (картинки), но раз уж есть CatalogBox и можно делать выбор с удобными фильтрами, то хочется множественный CatalogBox. Тут естественны функции: добавить, убрать. Иногда требуется ввести валидацию на количество выбранных элементов – расширение required.

    Например, нужно в заказ добавлять товары и хочется дать возможность пользователю выбирать их сразу несколько, но CheckBoxList неудобен ввиду большого количества товаров. Тогда пользователю будет удобно в каталоге с помощью фильтров выбрать несколько товаров, нажать «Добавить», и потом, при необходимости, добавить еще.
    Визуальный пример:



    Как видно, в левом столбце грида стоит CheckBox – таким образом можно выбирать несколько элементов.

    Эта возможность уже полностью ломает ComboBox – он не предназначен для хранения нескольких выбранных значений. Получаем для общего случая творческую изобретательскую задачу, вариативную в реализации.

    Приведу визуальный пример сделанного выбора.
    — Если выбран 1 элемент:



    — Если выбрано 2 элемента:



    — А так можно просмотреть список выбранных элементов и удалить ненужные:


  6. Иногда необходима возможность выбрать какой-то один элемент из двух списков.
    Например, нужно выбрать кто будет доставлять заказ – либо сторонняя компания, либо свой курьер. Можно ввести общую родительскую сущность («исполнитель доставки»), но нет смысла в странице-каталоге для нее. Поэтому оказывается нужна возможность выбора в один ComboBox из разных списков.

    Удобнее всего для пользователя этот выбор реализовать на одном контроле CatalogBox, но сделать 2 (или более) кнопочки, открывающие разные страницы-каталоги (разных сущностей). И как значение хранить не только выбранный объект, но и его сущность.

    Пример:



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

Практически в любом веб-приложении очень нужны первые 4 пункта – кнопка «сбросить значение», выделение изменений, ссылка на страницу выбранного элемента и выбор с полноценными фильтрами. Остальные дополнения нужны далеко не всем проектам. Но для большой информационной системы кажется в любом случае необходимыми все пункты.

Полные Функциональные Требования


CatalogBox


  1. Кнопка-треугольник (показывающая список в виде обычного выпадающего списка):

    a. Возможность задать настройками, показывать или нет кнопку-треугольник.
    Для больших списков кнопка «показать весь список» может не иметь большого значения, имеет значение только фильтрованный список. А выбирать критерий, большой это список или нет, должен архитектор интерфейса, а не сам контрол – поэтому нужна настройка.
    b. Для разнородного выбора (выбора значения из двух списков) нужно либо делать более одной кнопки-треугольника, либо ни одной, если созданы кнопки-троеточия (открывающие модальную страницу-каталог).
    c. Открывать ли список при нажатии на контрол.
    d. Открывать ли список при фокусе на контрол.
  2. Кнопка-крестик (сбрасывающая выбранное значение).

    a. Связана с валидацией. Если выбор обязателен – то крестика не должно быть.
    b. Для множественного выбора – очистить полностью выбор. Стоит также сделать кнопку удаления одного выбранного значения.
  3. Ввод текста в контроле и выбор элемента:

    Идеальным кажется такое поведение. Пользователь вводит текст, ищутся элементы, показываются найденные (с учетом авторизационного фильтра, заданного фильтра, фильтра от выбора значений в других контролах, настроек окна virtual scrolling). При потере фокуса выбирается:
    — Ничего не найдено: выбор не меняется.
    — Найден 1 элемент: выбирается он.
    — Найдено больше 1: настройка: выбирается либо первый, либо выбранный до этого.
    Выбор элемента мышкой, скролом, стрелками-ентером. Список либо полный, либо подкачивается по мере надобности (virtual scrolling).
  4. Поиск элементов, фильтры:
    Фильтр по введенной строке – сортировка: 1) имя равно введенной строке, 2) имя начинается с нее, 3) кончается на нее, 4) внутри нее.

    Необходимые фильтры:

    a. Заданный постоянный фильтр для этого инстанса контрола;
    b. Продуцированный другими контролами страницы фильтр;
    c. Авторизационный фильтр. Этот фильтр должен накладываться на серверной стороне – это правило безопасности.
    Передача всех этих фильтров в страницу-каталог с указанием, что пользователю нельзя их менять.
  5. Отображение найденных элементов:

    a. Возможность табличного вида, шаблоны ячейкам, стили/форматы.
    b. Выделение найденного текста в элементе.
  6. Отображение выбранного (выбранных при множественном выборе) элемента:
    Теоретически возможные варианты:
    — шаблон для js-аналога string.Format с указанием path’ов (например, «{Name} ({Id})»);
    — текстовая js-функция;
    — Html шаблон.
    Если мы остаемся в рамках исходного тега html select, то возможны только текстовые варианты, а если разметка полностью кастомная, то простор для фантазии есть.
  7. Маркер «значение изменено» с показом старого значения в title (всплывающей подсказке).
  8. Title или baloon для показа информации о выбранном элементе, не поместившейся в видимую область бокса.
  9. Ссылка на страницу выбранного элемента.
    Учесть, что не у всех сущностей есть страница (но у всех элементов, если есть у сущности).
  10. Кнопка-троеточие.
    Открывает страницу-каталог данной сущности в модальном окне. После выбора в каталоге элемента он передается в CatalogBox.
  11. Разнородный выбор.
    Более одной кнопки-троеточия, открывающих разные каталоги в модальном окне. Настройка иконок для кнопок, title.
  12. Множественный выбор.
    Отображение более одного выбранного значения, удалить одно или все сразу.
  13. Разнородный множественный выбор.
  14. Если стиль сайта этого требует, то кнопочки показывать только при наведении мышки на CatalogBox.
  15. Валидация. Показывать состояние невалидности только после нажатия кнопки.

Страница-каталог


  1. Может открываться как независимо, по ссылке, так и модально, по нажатию на кнопку-троеточие.
  2. Фильтр как внешний параметр, в querystring. Возможности фильтра должны позволять фильтрацию, необходимую для CatalogBox’а.
  3. Кнопка «сохранить фильтр в буфере обмена» — чтобы послать ссылку, по которой откроется точно выбранный список.
    Также в querystring можно сохранять сортировку и пейджинг.
  4. Параметр, определяющий, можно ли переданный фильтр пользователю изменить (только переданный). Нужен, чтобы CatalogBox мог открыть свой каталог, в котором пользователь не смог бы выбрать ничего запрещенного.
  5. Для модального режима параметр — одиночный/множественный выбор.
    Для множественного выбора, скорее всего, самый удобный пользователю вариант — чтобы показывался checkbox на каждый элемент.
  6. Способ отображения списка элементов — обычно grid. Но может быть и list или tree.
  7. Кнопка «обновить» — чтобы можно было обновить список без обновления страницы, то есть без сбрасывания выбранных фильтров.
  8. Кнопка «сбросить фильтр». Но не сбрасывать переданные во внешнем параметре фильтры из п2.

    Для модального режима (то есть при связке с CatalogBox’ом):

  9. Без шапки, без футера, меню и прочего, что не касается непосредственно выбора элемента.
  10. Все ссылки на странице должны открываться в новом окне/вкладке (target=”_blank”).
  11. Кнопка «выбрать». Пока не выбран ни один элемент, disabled. Когда выбирается первый, становится активна. При нажатии каким-либо образом шлет выбранный элемент (или элементы) породившему CatalogBox’у.
  12. Кнопка «Отмена». При нажатии закрывает модальное окно. Так же, как и кнопка-крестик.
  13. При повторном открытии есть два варианта — перезагрузить страницу или не перезагрузить, так, чтобы остались выбранными фильтры/сортировка/пейджинг.
  14. Отображение с учетом авторизации – пользователю может быть недоступна какая-то часть списка элементов. Или даже какие-то фильтры. Но это правило для всего сайта, страница-каталог тут ничем не отличается.

PS


Коллеги, прошу вас, если знаете, где реализована похожая функциональность выбора объекта с помощью полнофункциональной страницы-каталога, пишите в коментах. Я нигде — по крайней мере, в веб-мире — не видел подобных реализаций.
Tags:
Hubs:
+4
Comments6

Articles

Change theme settings