Рендеринг форм
Внешний вид форм может быть очень разнообразным. На практике мы можем
столкнуться с двумя крайностями. С одной стороны, в приложении
необходимо отобразить ряд форм, визуально похожих друг на друга, и мы
ценим простоту визуализации без шаблона с помощью $form->render()
.
Обычно это относится к административным интерфейсам.
С другой стороны, существуют различные формы, каждая из которых уникальна. Их внешний вид лучше всего описывать с помощью языка HTML в шаблоне. И конечно, помимо обеих упомянутых крайностей, мы встретим множество форм, которые находятся где-то посередине.
Рендеринг с помощью Latte
Система шаблонов Latte в корне облегчает отрисовку форм и их элементов. Сначала мы покажем, как отрисовывать формы вручную, элемент за элементом, чтобы получить полный контроль над кодом. Позже мы покажем, как автоматизировать такой рендеринг.
Предложение шаблона Latte для формы можно сгенерировать с
помощью метода Nette\Forms\Blueprint::latte($form)
, который выведет его на
страницу браузера. Затем достаточно выделить код щелчком мыши и
скопировать его в свой проект.
{control}
Самый простой способ отобразить форму – написать ее в шаблоне:
Внешний вид отрисованной формы можно изменить, настроив Renderer и отдельные элементы управления.
n:name
Очень легко связать определение формы в PHP-коде с HTML-кодом. Просто
добавьте атрибуты n:name
. Вот как это просто!
Внешний вид получившегося HTML-кода полностью в ваших руках. Если вы
используете атрибут n:name
с <select>
, <button>
или
<textarea>
элементами, их внутреннее содержимое заполняется
автоматически. Кроме того, тег <form n:name>
тег создает локальную
переменную $form
с нарисованным объектом формы, а закрывающий тег
</form>
перерисовывает все недорисованные скрытые элементы (то
же самое относится и к {form} ... {/form}
).
Однако не стоит забывать о выводе возможных сообщений об ошибках. Как
тех, которые были добавлены к отдельным элементам методом addError()
(с помощью {inputError}
), так и тех, которые были добавлены
непосредственно к форме (возвращаются методом $form->getOwnErrors()
):
Более сложные элементы формы, такие как RadioList или CheckboxList, могут быть отображены элемент за элементом:
{label}
{input}
Не хотите ли вы подумать для каждого элемента, какой HTML-элемент
использовать для него в шаблоне? <input>
, <textarea>
и т.д.?
Решением является универсальный тег {input}
:
Если форма использует переводчик, то текст внутри тегов {label}
будет переведен.
Опять же, более сложные элементы формы, такие как RadioList или CheckboxList, могут выводиться поэлементно:
Чтобы отобразить <input>
в элементе Checkbox, используйте
{input myCheckbox:}
. Атрибуты HTML должны быть разделены запятой
{input myCheckbox:, class: required}
.
{inputError}
Выводит сообщение об ошибке для элемента формы, если оно есть.
Сообщение обычно оборачивается в HTML-элемент для стилизации. Избежать
вывода пустого элемента при отсутствии сообщения можно с помощью
n:ifcontent
:
Мы можем определить наличие ошибки с помощью метода hasErrors()
и
установить класс родительского элемента соответствующим образом:
{form}
Теги {form signInForm}...{/form}
являются альтернативой
<form n:name="signInForm">...</form>
.
Автоматический рендеринг
С помощью тегов {input}
и {label}
мы можем легко создать общий
шаблон для любой формы. Он будет итерировать и последовательно
выводить все элементы формы, за исключением скрытых элементов, которые
выводятся автоматически при завершении формы с помощью тега
</form>
тега. Он будет ожидать имя отрисованной формы в
переменной $form
.
Используемые парные самозакрывающиеся теги {label .../}
отображают метки, поступающие из определения формы в PHP-коде.
Вы можете сохранить этот общий шаблон в файле basic-form.latte
и для
рендеринга формы просто включить его и передать имя формы (или
экземпляр) в параметр $form
:
Если вы хотите повлиять на внешний вид одной конкретной формы и отрисовать один элемент по-другому, то самый простой способ – это подготовить в шаблоне блоки, которые можно перезаписать позже. Блоки также могут иметь динамические имена, поэтому вы можете вставить в них имя элемента, который нужно нарисовать. Например:
Для элемента, например, username
создается блок input-username
,
который можно легко переопределить с помощью тега {embed}:
Альтернативно, все содержимое шаблона basic-form.latte
может быть определено как блок, включая
параметр $form
:
Это несколько упростит его использование:
Вам нужно будет импортировать блок только в одном месте, в начале шаблона макета:
Особые случаи
Если необходимо отобразить только внутреннюю часть формы без
HTML-тегов <form>
например, при отправке сниппетов, скройте их с
помощью атрибута n:tag-if
:
Тег formContainer
помогает при отрисовке вводимых данных внутри
контейнера формы.
Рендеринг без Latte
Самый простой способ отобразить форму – вызвать:
Внешний вид отрисованной формы можно изменить, настроив Renderer и отдельные элементы управления.
Рендеринг вручную
Каждый элемент формы имеет методы, которые генерируют HTML код для поля и метки формы. Они могут возвращать его в виде строки или объекта Nette\Utils\Html:
getControl(): Html|string
возвращает HTML-код элементаgetLabel($caption = null): Html|string|null
возвращает HTML-код метки, если таковая имеется
Это позволяет отображать форму элемент за элементом:
В то время как для некоторых элементов getControl()
возвращает один
HTML-элемент (например. <input>
, <select>
и т.д.), для других
он возвращает целый кусок HTML-кода (CheckboxList, RadioList). В этом случае можно
использовать методы, генерирующие отдельные входы и метки, для каждого
элемента отдельно:
getControlPart($key = null): ?Html
возвращает HTML-код одного элемента.getLabelPart($key = null): ?Html
возвращает HTML-код для метки отдельного элемента
Эти методы имеют префикс get
по историческим причинам,
но generate
было бы лучше, так как он создает и возвращает новый
элемент Html
при каждом вызове.
Рендерер
Это объект, обеспечивающий рендеринг формы. Он может быть установлен
методом $form->setRenderer
. Ему передается управление при вызове
метода $form->render()
.
Если мы не зададим пользовательский рендерер, будет использоваться рендерер по умолчанию Nette\Forms\Rendering\DefaultFormRenderer. В результате элементы формы будут отображены в виде HTML-таблицы. Вывод выглядит следующим образом:
Использовать таблицу или нет – решать вам, многие веб-дизайнеры
предпочитают другую разметку, например, список. Мы можем настроить
DefaultFormRenderer
так, чтобы он вообще не выводился в таблицу. Мы просто
должны установить соответствующие $wrappers.
Первый индекс всегда представляет область, а второй – элемент. Все
соответствующие области показаны на рисунке:

По умолчанию группа controls
обернута в. <table>
и каждый
pair
представляет собой строку таблицы <tr>
содержащая
пару label
и control
(ячейки <th>
и <td>
).
Давайте изменим все эти элементы обертки. Мы завернем controls
в
<dl>
, оставим pair
в одиночестве, поместим label
в
<dt>
и обернем control
в <dd>
:
В результате получится следующий фрагмент:
Обертки могут влиять на многие атрибуты. Например:
- добавить специальные классы CSS к каждому вводу формы
- различать четные и нечетные строки
- по-разному рисовать обязательные и необязательные элементы
- установить, будут ли сообщения об ошибках показываться над формой или рядом с каждым элементом
Опции
Поведением Renderer также можно управлять, устанавливая опции для отдельных элементов формы. Таким образом, вы можете установить всплывающую подсказку, которая будет отображаться рядом с полем ввода:
Если мы хотим поместить в него HTML-контент, мы используем класс Html.
Html-элемент также можно использовать вместо label:
$form->addCheckbox('conditions', $label)
.
Группировка входов
Поля ввода можно объединить в наборы визуальных полей, создав группу:
Создание новой группы активирует её — все добавленные далее элементы добавляются в эту группу. Вы можете построить форму следующим образом:
Сначала рендерер отрисовывает группы, а затем элементы, не принадлежащие ни к одной из групп.
Поддержка Bootstrap
Вы можете найти примеры настройки рендерера для Twitter Bootstrap 2, Bootstrap 3 и Bootstrap 4
Атрибуты HTML
Чтобы задать произвольные HTML-атрибуты для элементов формы,
используйте метод setHtmlAttribute(string $name, $value = true)
:
Указание типа элемента:
Установка типа и других атрибутов служит только для визуальных целей. Проверка правильности ввода должна происходить на сервере, что можно обеспечить, выбрав соответствующий элемент управления формой и задав правила проверки.
Для отдельных элементов в списках радио- или чекбоксов мы можем
задать HTML-атрибут с разными значениями для каждого из них. Обратите
внимание на двоеточие после style:
, которое обеспечивает выбор
значения на основе ключа:
Отображается как:
Для задания булевых атрибутов, таких как readonly
, можно
использовать обозначение с вопросительным знаком:
Отображается как:
Для селекбоксов метод setHtmlAttribute()
устанавливает атрибуты
элемента <select>
. Если мы хотим установить атрибуты для каждого
<option>
, мы будем использовать метод setOptionAttribute()
. Кроме
того, двоеточие и вопросительный знак, использованные выше,
работают:
Отображается как:
Прототипы
Альтернативным способом установки атрибутов HTML является изменение
шаблона, на основе которого генерируется элемент HTML. Шаблон является
объектом Html
и возвращается методом getControlPrototype()
:
Шаблон метки, возвращаемый методом getLabelPrototype()
, также может
быть изменен таким образом:
Для элементов Checkbox, CheckboxList и RadioList вы можете повлиять на шаблон
элемента, который оборачивает элемент. Его возвращает
getContainerPrototype()
. По умолчанию это „пустой“ элемент, поэтому
ничего не отображается, но если дать ему имя, он будет отображаться:
В случае CheckboxList и RadioList можно также повлиять на шаблон разделителя
элементов, возвращаемый методом getSeparatorPrototype()
. По умолчанию это
элемент <br>
. Если вы измените его на парный элемент, он будет
обволакивать отдельные элементы вместо того, чтобы разделять их. Также
можно влиять на шаблон HTML-элемента меток элементов, который возвращает
метод getItemLabelPrototype()
.
Перевод
Если вы программируете многоязычное приложение, то вам, вероятно, потребуется отображать форму на разных языках. В Nette Framework для этого определен интерфейс перевода Nette\Localization\Translator. В Nette нет реализации по умолчанию, вы можете выбрать в соответствии с вашими потребностями из нескольких готовых решений, которые можно найти на Componette. В их документации описано, как настроить переводчик.
Форма поддерживает вывод текста через переводчик. Мы передаем его с
помощью метода setTranslator()
:
С этого момента не только все метки, но и все сообщения об ошибках или записи в поле выбора будут переведены на другой язык.
Можно установить другой переводчик для отдельных элементов формы
или полностью отключить перевод с помощью null
:
Для правил валидации переводчику также передаются определенные параметры, например, для правила:
транслятор вызывается со следующими параметрами:
и таким образом может выбрать правильную форму множественного числа
для слова characters
по счету.
Событие onRender
Непосредственно перед отображением формы мы можем вызвать наш код. Это может, например, добавить HTML-классы к элементам формы для правильного отображения. Добавим код в массив ‚onRender‘: