#symfony #twig
#symfony #twig
Вопрос:
Я пытался вызвать виджет формы в своей форме несколько раз с разными атрибутами. Я получаю сообщение об ошибке — Field "x" has already been rendered, save the result of previous render call to a variable and output that instead.
Я исправил все места, которые мог, но есть некоторые поля, для которых нужны разные атрибуты. Например :-
form_widget(foo.bar, {'value' : 'image'}) }}
и
form_widget(foo.bar, { 'attr': { 'class': 'hidden' }} )
Есть ли возможность вызвать виджет формы с разными параметрами в одной и той же форме?
Ответ №1:
Повторное использование одного и того же виджета несколько раз, как вы это делаете, может иметь странные побочные эффекты, потому что Symfony также установит идентификатор html, и в зависимости от того, где вы размещаете поле, вы можете получить неверный html, который, например, может привести к поломке вашего JavaScript / делать странные вещи или сделать отправку форм ненадежной.
Самый безопасный способ убедиться, что у вас есть действительный HTML (например, без дублированного идентификатора), — это вручную отобразить каждый элемент, а затем использовать только элементы формы для получения текущего содержимого / ошибок. Чтобы сделать это, вы можете игнорировать form_widget
помощники form_row
и и просто написать HTML для полей самостоятельно, а затем вставлять только те части, которые вам нужны, например
<input name="{{ field_name(foo.bar) }}" type="file">
Для этого точного примера требуется Symfony 5.2, потому field_name()
что он новый. См. https://symfony.com/blog/new-in-symfony-5-2-form-field-helpers
Недостатком является то, что такие вещи, как {{ form_rest(form) }}
, вероятно, больше не будут работать, но, по крайней мере, вы все равно можете использовать любой помощник, который выводит только часть формы, которая не является элементом формы, например form_error
, form_label
все равно должен работать, но form_widget
и form_row
вам следует избегать. form_end
снова отображает все оставшиеся поля, поэтому вам, вероятно, также следует избегать этого. Более конкретные помощники, представленные в Symfony 5.2, также очень удобны для этого подхода. Таким образом, у вас есть полный контроль над тем, как отображаются поля, и вы можете изменять классы для каждого поля, которое вы используете в нескольких местах.
Если вы используете более старую версию Symfony, вы можете самостоятельно реализовать вспомогательные методы, взглянув на TwigExtension, который их предоставляет, и настроив его для своего приложения, например, предоставьте свой собственный AppTwigExtension с аналогичными функциями.
Если вы хотите продолжать использовать form_widget
/ form_row
, вам следует избегать многократного отображения одной и той же формы (элементов) в одном запросе. Вы можете попробовать использовать что-то вроде вложенных запросов / ESI, но это, вероятно, будет халтурно.
Существует способ рендеринга формы несколько раз, позволяющий каждый раз отображать ее по-разному. Например, вы можете создать FormCollection с добавлением одного и того же типа дважды. Тогда у вас есть одна форма, которая содержит 2 формы (ваша форма дважды). Вы также можете создать несколько экземпляров для одной и той же формы, а затем отобразить их по-разному в своем шаблоне в зависимости от того, какой из них вы используете (foo или bar), например, что-то в этом роде (только грубый набросок, не уверен, что это точно сработает):
public function contact(Request $request): Response
{
$form1 = $this->createForm(FooFormType::class, null, ['attr' => ['id' => 'form1']]);
$form1->handleRequest($request);
if ($form1->isSubmitted() amp;amp; $form1->isValid() {
// ...
}
$form2 = $this->createForm(FooFormType::class, null, ['attr' => ['id' => 'form1']]);
$form2->handleRequest($request);
if ($form2->isSubmitted() amp;amp; $form2->isValid() {
// ...
}
// Do something
return $this->render('....html.twig', [
'foo' => $form1->createView(),
'bar' => $form2->createView(),
]);
}
Как вы можете видеть, это немного избыточно, поэтому, как правило, вы хотите избежать этого подхода, но вы должны найти несколько примеров в Интернете людей, делающих что-то подобное.