Pull to refresh

Что нужно от форм?

Reading time5 min
Views8.6K

В жизни каждого разработчика наступает такой момент, когда ему нужно сделать форму. Вроде бы чего тут сложного — бери, бросай. А нет, форма то, она как живая. У неё есть своё настроение, свои привычки. Выбрал пол — “Ж”, она преобразилась, стала чуть другой, любопытной, спрашивает замужем ли, любимые духи, обувь с каблуком, или без? Но ты же мужик! И тут выбираешь пол “М”, и, как бы, вопросы должны быть другие — холост, любимый сорт пива, любимый спорт. Конечно, можно понаделать кучу формочек для каждого чиха, если “М”, то одна, если “Ж”, то другая. Но такой метод обернется катастрофой на этапе поддержки, да и вообще не в духе красивого кода. Поэтому форма должна быть умной. Очень умной. Она должна знать кто её трогает, чего он хочет, его потаённые желания. Например: есть форма ввода адреса в пять полей
  • страна
  • область
  • город
  • улица
  • метро

Выбираю я город, и почему бы форме не додумать область и страну? Или выбрал Владимирскую область, зачем мне в списке городов “Москва”? Поле “метро” для Владимирской области тоже не актуально, а когда выбран город Струнино, так вообще издевательство. Занимаясь разработкой клиентской части в корпоративных WEB приложениях вот уже 5 лет я таки познал, как сделать форму умной. Надеюсь, мой опыт будет полезен и вам.

Основные требования к формам в ERP системах следующие:
  • В зависимости от данных меняется набор полей и их атрибуты (обязательность ввода, доступность для редактирования).
  • В зависимости от значений одних полей фильтруются значения других полей.
  • При вводе форма может изменять значения полей и их атрибуты.

Так или иначе, это решается двумя способами:
  1. Много узкоспециализированных форм сдобренных мастерами.
  2. Универсальные формы, меняющие свое состояние по множеству событий (как минимум при изменении значений).

В первом случае все выходит довольно печально. Возьмем для примера ветвление по полу. Чтоб не донимать пользователя лишними полями сначала узнаем пол, а потом выводим актуальную для этого выбора форму. Выходит как-то так:


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

Как правило, есть поля, логика которых идентична для всех веток. Самое простое — дублировать эту логику, но это же и самое неправильное. Очень быстро разработчик утонет в собственном коде, а о конфигурировании через настройки и говорить не приходится, они тоже дублируются. А ещё ветвление имеет тенденцию нарастать, а дерево — становиться сложным графом.

Эффективнее иметь одну форму на один бизнес объект (сущность), изменяющую свое представление по различным событиям. Тут на выручку приходит второй способ — универсальные, динамически изменяемые формы (хотя деление условно, мастер может строиться на таких формах). Реализовать его несколько сложнее, чем ветвление. Раньше я думал “что тут сложного”, но в процессе решения этой задачи количество граблей, подводных камней и тонких материй имело тенденцию плодиться неимоверно! Пройдя все это, я просто не могу не поделиться своей болью и опытом.

Элементы динамики


Хорошо, ну будем что-то там прятать, что-то показывать, где-то фильтровать… Стоп стоп! Не все так просто. Во первых есть три основных вещи, которыми нужно управлять:

  1. Видимость
  2. Обязательность
  3. Доступность


Если с доступностью и обязательностью все более менее понятно, то вот видимость — вещь далеко не тривиальная, и управление ею тесно связано со способом размещения полей (пошли подводные камни).

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

Фиксированные формы


С полями, фиксированными в абсолютных координатах (absolut layout есть везде), работать в плане размещения проще — сделал сетку для выравнивания и мышкой расставляй поля как душе угодно, просто, непринужденно. Бывает что поле должно быть не больше чем 40em, ну хоть убейся, а с фиксированными размерами — нет проблем, сорок, так сорок. Проблемы начинаются когда начинается управление видимостью. Вот есть три поля, прячется центральное, остается дырка:

Как же эту дырку закрыть? Предположим тут мы это узнаем, а если структура сложнее? Скажем 3 колонки колонки и группа полей? Не будем же мы все это замерять и пересчитывать.

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

Резиновые формы


А что же будет с резиновыми формами, которые не фиксированы в абсолютных координатах? Будет все прекрасно! Дырка просто схлопнется:


Схлопывание — это основная проблема при изменении видимости полей. Пользователю хочется видеть красивую, наполненную смыслом, а не пустотами форму.

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

На форме все что не поля — это контейнеры (мы пока будем рассматривать такую концепцию). А контейнеры содержат поля. А поля могут стать невидимыми, и контейнеры в этом случае окажутся пустыми. Пустой контейнер хуже дырки на форме. Он должен уйти в подполье вслед за своими полями. Но вот незадача, контейнеры могут быть вложенные, много раз вложенные и очень много раз вложенные (другие мне не попадаются). Возникает необходимость обхода дерева контейнеров на предмет наличия видимых полей в них. Обход, к счастью, вниз. В любом случае форма будет стремиться к иерархии, вроде такой:



Кажется алгоритм простой — изменили состояние видимости поля, обошел контейнер её содержащий вниз, до первого видимого поля. Нашли такое поле — баста, контейнер видим, не нашел — контейнер прячется, и соответственно, повторяем для родительского контейнера ту же процедуру. Это одно из решений.
Иногда ещё и хочется спрятать не отдельные поля, а целиком весь контейнер. Появляется признак некой абсолютной спрятанности контейнера, чтоб он не вылез даже если поле в нем “видимо”. Довольно быстро этот механизм нарастает и усложняется, лучше сразу задуматься, где все будет считаться, на сервере или на клиенте, или смежно. Разделение ответственности в этом месте очень важно.

А от куда берется динамика?


Она берется с сервера (К.О.). По сути это набор каких-то правил, которые (сильно желательно) задаются пользователем через интерфейс. Простейшим кирпичиком динамики является ПУЗ (Поле-Условие-Значение). Упрощенно это выражение вида: “Если значение поля равно значению, то поле видимо, иначе не видимо”. Условие сравнивает некое значение из какого-то поля на форме с эталоном, и, в зависимости от выбранного условия, поле, к которому относится этот ПУЗ, изменяет свое состояние (видимость, доступность, обязательность). Например в этой форме есть ПУЗ скрытия поля «Метро», если в городе его нет. Вот на таких элементарных условиях строится динамика. Конечно она может быть не только на ПУЗ-ах. Это могут быть и статусы документов, и доступные поля в операции, и много страшных слов. Но на уровне клиента — это все абстракция и не суть откуда приходит, важно как это отрабатывать.

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

Резюме...


Буквами выше я поведал о том, как делается динамика для форм. Задача довольно тривиальная и во многом зависит от компонентов, которые вы используете для интерфейса. Я описал, как это делается в Web, хотя настолько обще, что подойдет множеству систем. Об описанных мною нюансах стоит подумать сразу же, как начинаете думать о том, чтобы начать думать об архитектуре формы в своей системе.

Немного позже (если будет интерес) я расскажу подробнее о источниках динамики, а именно — событиях полей, динамических фильтрах, глубже скажу про ПУЗ-ы, и коснусь статусов и операций. Все это общие темы для учетных систем, и не только.
Tags:
Hubs:
Total votes 61: ↑52 and ↓9+43
Comments74

Articles