Как настроить атрибут data-prototype в формах Symfony 2

47

Начиная с 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>

Есть ли у кого-нибудь идея сделать этот взлом?

Теги:
forms
collections

11 ответов

67

Немного устарел, но вот это смертельно-простое решение.

Идея состоит в том, чтобы просто визуализировать элементы коллекции через шаблон 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

  • 0
    Помогло, спасибо :)
  • 1
    Тег веточки фильтра должен заканчиваться одной фигурной скобкой, а не двумя. @Jivan Можете ли вы отредактировать его, поскольку мы не можем редактировать пост только для одного персонажа?
Показать ещё 8 комментариев
46

Я знаю, что этот вопрос довольно старый, но у меня была такая же проблема, и именно так я его любил. Я использую веточку 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

  • 1
    Хороший, спасибо!
  • 0
    Я не могу на всю жизнь заставить это функционировать. Вы знаете, действительно ли это все еще для Symfony2.5?
Показать ещё 7 комментариев
24

Вероятно, вы узнали об этом, но вот решение для других.

Создайте новый шаблон и скопируйте/вставьте в него этот код: https://gist.github.com/1294186

Затем в шаблоне, содержащем форму, которую вы хотите настроить, примените ее к своей форме, выполнив следующее:

{% form_theme form 'YourBundle:Deal:Theme/_field-prototype.html.twig' %}
  • 2
    Шаблон идеально подходит для перебора коллекций и визуализации всей коллекции по вашему желанию. Merci
  • 1
    спасибо миллион, идеальный шаблон
Показать ещё 3 комментария
5

Недавно я столкнулся с подобной проблемой. Здесь, как вы можете переопределить прототип коллекции, не указывая явно в 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>

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

  • 0
    Он может работать для добавленной вручную подформы, но в моем случае он не работает с под формами, автоматически созданными из поля сущностей (т.е. при обновлении, если некоторые элементы коллекции уже существуют).
5

Я знаю, что ответ очень поздний, но он может быть полезен для посетителей.

в вашем файле темы вы можете просто использовать один блок для рендеринга каждой коллекции элементов виджета веб-сайтов следующим образом:

{% 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 %}

теперь прототип и сделанная запись коллекции будут одинаковыми.

2

У меня была несколько схожая проблема. Возможно, вам придется настроить это, чтобы работать на ваше дело, но кто-то может оказаться полезным.

Создайте новый файл шаблона, чтобы сохранить свою собственную тему темы

./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) будет отображать только поле и ничего больше.

1

Вот пример кода для пользовательских прототипов данных:

{{ form_widget(form.emails.get('prototype')) | e }}

где emails - ваша коллекция.

  • 7
    Как это принято? Разве это не прототип данных по умолчанию?
1

Прикладная широкоформатная тематика будет применена к прототипу. См. Внедрение приложений в целом

0

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

{# 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>
0

Чтобы настроить различные прототипы 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 %}
-1

В этом сообщении основное внимание уделяется использованию ранее существовавших соглашений в шаблоне веток.

Исходя из "Как вставить коллекцию форм" из Поваренной книги 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="&lt;tr&gt;  &lt;td&gt;&lt;div&gt;&lt;input type=&quot;text&quot; id=&quot;task_tags__name__tagId&quot; name=&quot;task[tags][__name__][taskId]&quot; disabled=&quot;disabled&quot; required=&quot;required&quot;    size=&quot;10&quot; value=&quot;&quot; /&gt;&lt;/div&gt;&lt;/td&gt; &lt;td&gt;&lt;div&gt;&lt;input type=&quot;text&quot; id=&quot;task_tags__name__tagName&quot; name=&quot;task[tags[__name__][tagName]&quot; required=&quot;required&quot; value=&quot;&quot; /&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;">
    <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, но я не видел никаких объяснений, поэтому я думаю, что это, вероятно, более динамичный метод, который я получу в один из этих ближайших дней.

Мир, Стив

Update:

Можно также использовать только части прототипа:

data-prototype="&lt;tr&gt;  &lt;td&gt;{{ form_row(form.tags.vars.prototype.tagId) | e }}&lt;/td&gt; &lt;td&gt;{{ form_row(form.tags.vars.prototype.tagName) | e }}&lt;/td&gt;&lt;/tr&gt;"

Если атрибут типа данных таблицы с вышеприведенными тегами класса является версией с 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" ), когда страница отображается. Таким образом, любая настройка на уровне поля не теряется, но! вы должны вручную добавить и удалить поля в прототипе, как вы это делаете с сущностью:)

  • 0
    Добавление жестко закодированного кода формы в атрибут prototype лишает смысла динамически генерировать формы в Symfony. Вам не нужно обновлять свой прототип при добавлении или удалении некоторых полей.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню