Начиная с umpteens days, я блокирую проблему с Symfony 2 и формы.
У меня появилась форма веб-сайтов. "Веб-сайты" - это коллекция веб-сайтов, и каждый веб-сайт содержит два атрибута: "тип" и "URL".
Если я хочу добавить больше одного веб-сайта в свою базу данных, я могу нажать ссылку "Добавить другой сайт", которая добавит еще одну строку сайта в мою форму. Поэтому, когда вы нажимаете кнопку "Отправить", вы можете добавить один или X веб-сайт одновременно.
В этом процессе для добавления строки используется атрибут data-prototype, который может генерировать суб-форму сайта.
Проблема в том, что я настраиваю свою форму, чтобы иметь отличную графическую визуализацию... например:
<div class="informations_widget">{{ form_widget(website.type.code) }}</div>
<div class="informations_error">{{ form_errors(website.type) }}</div>
<div class="informations_widget">{{ form_widget(website.url) }}</div>
<div class="informations_error">{{ form_errors(website.url) }}</div>
Но прототип данных не заботится об этой настройке, с тегами и свойствами HTML и CSS. Я сохраняю рендеринг Symfony:
<div>
<label class=" required">$$name$$</label>
<div id="jobcast_profilebundle_websitestype_websites_$$name$$">
<div>
<label class=" required">Type</label>
<div id="jobcast_profilebundle_websitestype_websites_$$name$$_type">
<div>
<label for="jobcast_profilebundle_websitestype_websites_$$name$$_type_code" class=" required">label</label>
<select id="jobcast_profilebundle_websitestype_websites_$$name$$_type_code" name="jobcast_profilebundle_websitestype[websites][$$name$$][type][code]" required="required">
<option value="WEB-OTHER">Autre</option>
<option value="WEB-RSS">Flux RSS</option>
...
</select>
</div>
</div>
</div>
<div>
<label for="jobcast_profilebundle_websitestype_websites_$$name$$_url" class=" required">Adresse</label>
<input type="url" id="jobcast_profilebundle_websitestype_websites_$$name$$_url" name="jobcast_profilebundle_websitestype[websites][$$name$$][url]" required="required" value="" />
</div>
</div>
</div>
Есть ли у кого-нибудь идея сделать этот взлом?
Немного устарел, но вот это смертельно-простое решение.
Идея состоит в том, чтобы просто визуализировать элементы коллекции через шаблон Twig, поэтому у вас есть полная возможность настроить прототип, который будет помещен в тэг data-prototype="..."
. Как если бы это была обычная, обычная форма.
В файле yourMainForm.html.twig:
<div id="collectionContainer"
data-prototype="
{% filter escape %}
{{ include('MyBundle:MyViewsDirectory:prototype.html.twig', { 'form': form.myForm.vars.prototype }) }}
{% endfilter %}">
</div>
И в MyBundle: MyViewsDirectory: prototype.html.twig:
<div>
<!-- customize as you wish -->
{{ form_label(form.field1) }}
{{ form_widget(form.field1) }}
{{ form_label(form.field2) }}
{{ form_widget(form.field2) }}
</div>
Кредит: адаптирован из https://gist.github.com/tobalgists/4032213
Я знаю, что этот вопрос довольно старый, но у меня была такая же проблема, и именно так я его любил. Я использую веточку macro
, чтобы выполнить это. Макросы похожи на функции, вы можете отображать их с разными аргументами.
{% macro information_prototype(website) %}
<div class="informations_widget">{{ form_widget(website.type.code) }}</div>
<div class="informations_error">{{ form_errors(website.type) }}</div>
<div class="informations_widget">{{ form_widget(website.url) }}</div>
<div class="informations_error">{{ form_errors(website.url) }}</div>
{% endmacro %}
теперь вы можете отображать этот макрос, где хотите. Обратите внимание, что information_prototype()
- это просто имя макроса, вы можете назвать его как хотите. Если вы хотите использовать макрос для отображения данных и прототипа таким же образом, сделайте следующее:
<div class="collection" data-prototype="{{ _self.information_prototype(form.websites.vars.prototype)|e }}">
{% for website in form.websites %}
{{ _self.information_prototype(website) }}
{% endfor %}
<button class="add-collection">Add Information</button>
</div>
form.websites.vars.prototype
содержит данные прототипа формы с указанным prototype_name
. Используйте _self.+macroname
, если вы хотите использовать макрос в том же шаблоне.
Вы можете узнать больше о макросах в документации Twig
Вероятно, вы узнали об этом, но вот решение для других.
Создайте новый шаблон и скопируйте/вставьте в него этот код: https://gist.github.com/1294186
Затем в шаблоне, содержащем форму, которую вы хотите настроить, примените ее к своей форме, выполнив следующее:
{% form_theme form 'YourBundle:Deal:Theme/_field-prototype.html.twig' %}
Недавно я столкнулся с подобной проблемой. Здесь, как вы можете переопределить прототип коллекции, не указывая явно в html:
{% set customPrototype %}
{% filter escape %}
{% include 'AcmeBundle:Controller:customCollectionPrototype.html.twig' with { 'form': form.collection.vars.prototype } %}
{% endfilter %}
{% endset %}
{{ form_label(form.collection) }}
{{ form_widget(form.collection, { 'attr': { 'data-prototype': customPrototype } }) }}
Вы можете делать все, что захотите, затем в своей пользовательской веточке. Например:
<div data-form-collection="item" data-form-collection-index="__name__" class="collection-item">
<div class="collection-box col-sm-10 col-sm-offset-2 padding-top-20">
<div class="row form-horizontal form-group">
<div class="col-sm-4">
{{ form_label(form.field0) }}
{{ form_widget(form.field0) }}
</div>
<div class="col-sm-3">
{{ form_label(form.field1) }}
{{ form_widget(form.field1) }}
</div>
<label class="col-sm-3 control-label text-right">
<button data-form-collection="delete" class="btn btn-danger">
<i class="fa fa-times collection-button-remove"></i>{{ 'form.collection.delete'|trans }}
</button>
</label>
</div>
</div>
Полезно, когда вам нужно только делать это в определенных местах и не нуждаться в глобальном переопределении, применимом ко всем коллекциям.
Я знаю, что ответ очень поздний, но он может быть полезен для посетителей.
в вашем файле темы вы можете просто использовать один блок для рендеринга каждой коллекции элементов виджета веб-сайтов следующим образом:
{% block _jobcast_profilebundle_websitestype_websites_entry_widget %}
<div class="informations_widget">{{ form_widget(form.type.code) }}</div>
<div class="informations_error">{{ form_errors(form.type) }}</div>
<div class="informations_widget">{{ form_widget(form.url) }}</div>
<div class="informations_error">{{ form_errors(form.url) }}</div>
{% endblock %}
также создайте тематический блок для вашей виджетной строки коллекции следующим образом:
{% block _quiz_question_answers_row %}
{% if prototype is defined %}
{%- set attr = attr | merge({'data-prototype': form_row(prototype) }) -%}
{% endif %}
{{ form_errors(form) }}
{% for child in form %}
{{ form_row(child) }}
{% endfor %}
{% endblock %}
теперь прототип и сделанная запись коллекции будут одинаковыми.
У меня была несколько схожая проблема. Возможно, вам придется настроить это, чтобы работать на ваше дело, но кто-то может оказаться полезным.
Создайте новый файл шаблона, чтобы сохранить свою собственную тему темы
./src/Company/TestBundle/Resources/views/Forms/fields.html.twig
Обычно вы можете использовать функцию form_row для отображения метки поля, ошибки и виджета. Но в моем случае я просто хотел отобразить виджет. Как вы говорите, использование функции прототипа данных также отображает метку, поэтому в наших новых файлах fields.html.twig введите свой код для того, как вы хотите, чтобы поле выглядело:
{% block form_row %}
{% spaceless %}
{{ form_widget(form) }}
{% endspaceless %}
{% endblock form_row %}
Я удалил контейнер div, метку и ошибку и просто оставил виджет.
Теперь в файле twig, который отображает форму, просто добавьте это после {% extends...%}
{% form_theme form 'CompanyTestBundle:Form:fields.html.twig' %}
И теперь form_widget (form.yourVariable.var.prototype) будет отображать только поле и ничего больше.
Вот пример кода для пользовательских прототипов данных:
{{ form_widget(form.emails.get('prototype')) | e }}
где emails
- ваша коллекция.
Прикладная широкоформатная тематика будет применена к прототипу. См. Внедрение приложений в целом
Если вам не нужно определять шаблон по всей системе, просто установите шаблон в шаблоне ветки и попросите его использовать его.
{# using the profiler, you can find the block widget tested by twig #}
{% block my_block_widget %}
<div >
<p>My template for collection</p>
<div >
{{ form_row(form.field1)}}
</div>
<div>
{{ form_row(form.field2)}}
</div>
</div>
{% endblock %}
{% form_theme form.my_collection _self %}
<button data-form-prototype="{{ form_widget(form.my_collection.vars.prototype) )|e }}" >Add a new entry</button>
Чтобы настроить различные прототипы VS-элементов существующего коллектора, вы можете переопределить collection_widget следующим образом:
{%- block collection_widget -%}
{% if prototype is defined %}
{%- set attr = attr|merge({'data-prototype': form_row(prototype, {'inPrototype': true} ) }) -%}
{% endif %}
{{- block('form_widget') -}}
{%- endblock collection_widget -%}
И затем в вашей пользовательской записи:
{% block _myCollection_entry_row %}
{% if(inPrototype is defined) %}
{# Something special only for prototype here #}
{% endif %}
{% endblock %}
В этом сообщении основное внимание уделяется использованию ранее существовавших соглашений в шаблоне веток.
Исходя из "Как вставить коллекцию форм" из Поваренной книги Symfony (http://symfony.com/doc/master/cookbook/form/form_collections.html), вы можете просто ввести любую форму html_escaped данные, которые вы хотите использовать в прототипе данных (может считаться взломом, но прекрасно работают), и только страницы, использующие этот шаблон, будут меняться.
В этом примере они сообщают вам:
<ul class="tags" data-prototype="{{ form_widget(form.tags.vars.prototype)|e }}">
...
</ul>
Это может быть успешно заменено чем-то вроде:
<table class="tags" data-prototype="<tr> <td><div><input type="text" id="task_tags__name__tagId" name="task[tags][__name__][taskId]" disabled="disabled" required="required" size="10" value="" /></div></td> <td><div><input type="text" id="task_tags__name__tagName" name="task[tags[__name__][tagName]" required="required" value="" /></div></td></tr>">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr>
...pre existing data here...
</tr>
</table>
Если атрибут типа данных таблицы с вышеприведенными тегами класса является версией с html-экранированием (и удалены строки, удаленные, хотя пробелы в порядке и требуются):
<tr>
<td><div><input type="text" id="task_tags__name__tagId" name="task[tags][__name__][taskId]" disabled="disabled" required="required" size="10" value="" /></div></td>
<td><div><input type="text" id="task_tags__name__tagName" name="task[tags[__name__][tagName]" required="required" value="" /></div></td>
</tr>
... но вы также должны настроить javascript в примере, чтобы добавить tr вместо li элементов:
function addTagForm(collectionHolder, $newLinkTr) {
...
// Display the form in the page in an tr, before the "Add a question" link tr
var $newFormTr = $('<tr></tr>').append(newForm);
...
};
...
// setup an "add a tag" link
var $addTagLink = $('<a href="#" class="add_tag_link">Add a tag</a>');
var $newLinkTr = $('<tr></tr>').append($addTagLink);
...
Для меня следующий шаг - выяснить, как определить прототип во внешнем файле, который я могу каким-то образом вызвать в шаблоне ветки для прототипа данных, который динамически работает с формой. Что-то вроде:
<table class="tags" data-prototype="{{somefunction('App\Bundle\Views\Entity\TagsPrototypeInTable')}}">
Итак, если один из других сообщений описывает это, и я слишком плотный, или если кто-то знает, как это сделать, скажите так!
Есть ссылка на что-то из gitHub от Francois, но я не видел никаких объяснений, поэтому я думаю, что это, вероятно, более динамичный метод, который я получу в один из этих ближайших дней.
Мир, Стив
Можно также использовать только части прототипа:
data-prototype="<tr> <td>{{ form_row(form.tags.vars.prototype.tagId) | e }}</td> <td>{{ form_row(form.tags.vars.prototype.tagName) | e }}</td></tr>"
Если атрибут типа данных таблицы с вышеприведенными тегами класса является версией с html-экранированием (и удалены строки, удаленные, хотя пробелы в порядке и требуются):
<td>{{ form_row(form.tags.vars.prototype.tagId) | e }}</td>
<td>{{ form_row(form.tags.vars.prototype.tagName) | e }}</td>
(я использовал http://www.htmlescape.net/htmlescape_tool.html.)
Symfony заменит информацию между {{}} окном html_escaped (из-за поля "| e" ), когда страница отображается. Таким образом, любая настройка на уровне поля не теряется, но! вы должны вручную добавить и удалить поля в прототипе, как вы это делаете с сущностью:)