Как настроить атрибут data-prototype в формах Symfony 2 - PullRequest
53 голосов
/ 26 сентября 2011

С нескольких дней я блокирую проблему с Symfony 2 и формами.

Я получил форму сущностей веб-сайтов.«Веб-сайты» - это набор сущностей веб-сайтов, и каждый веб-сайт содержит два атрибута: «тип» и «URL».

Если я хочу добавить больше одного веб-сайта в свою базу данных, я могу нажать «Добавить».ссылка на другой веб-сайт, которая добавляет еще одну строку веб-сайта в мою форму.Поэтому, когда вы нажимаете кнопку отправки, вы можете добавить один или несколько веб-сайтов одновременно.

В этом процессе для добавления строки используется атрибут data-prototype, который может генерировать вложенный веб-сайт.form.

Проблема в том, что я настраиваю свою форму так, чтобы она имела отличный графический рендеринг ... вот так:

<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>

У кого-нибудь есть идея сделать этот хак?

Ответы [ 11 ]

72 голосов
/ 26 января 2014

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

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

47 голосов
/ 26 июля 2013

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

25 голосов
/ 03 марта 2012

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

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

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

{% form_theme form 'YourBundle:Deal:Theme/_field-prototype.html.twig' %}
5 голосов
/ 14 октября 2015

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

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

5 голосов
/ 29 августа 2015

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

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

{% 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 голосов
/ 29 марта 2013

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

Создайте новый файл шаблона для хранения вашей пользовательской формы 'theme'

./src/Company/TestBundle/Resources/views/Forms/fields.html.twig

Обычно вы можете использовать функцию form_row для отображения метки поля, ошибки и виджета. Но в моем случае я просто хотел отобразить виджет. Как вы говорите, использование функции data-prototype также будет отображать метку, поэтому в нашем новом fields.html.twig введите свой пользовательский код для того, как вы хотите, чтобы поле выглядело:

{% block form_row %}
{% spaceless %}
        {{ form_widget(form) }}
{% endspaceless %}
{% endblock form_row %}

Я удалил контейнер div, а также метку и ошибку и просто покинул виджет.

Теперь в файле ветки, который отображает форму, просто добавьте это после {% extends ...%}

{% form_theme form 'CompanyTestBundle:Form:fields.html.twig' %}

А теперь form_widget (form.yourVariable.var.prototype) будет отображать только поле и ничего больше.

1 голос
/ 10 ноября 2011

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

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

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

1 голос
/ 27 сентября 2011

Приложение широкого круга тем будет применено к прототипу.См. Выполнение настроек для всего приложения

0 голосов
/ 27 сентября 2017

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

{# 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 голосов
/ 23 января 2017

Чтобы настроить по-разному существующие элементы коллекции против прототипа, вы можете переопределить 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 %}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...