Symfony:尝试自定义集合表单原型

Symfony:尝试自定义集合表单原型,symfony,Symfony,我有以下表格: class BillType extends AbstractType { /** * @param FormBuilderInterface $builder * @param array $options */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add

我有以下表格:

class BillType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
       $builder
        ->add('user')
        ->add('numberPlate')
        ->add('servicesPerformed', CollectionType::class, array(
             'label' => false,
             'entry_type' => ServicePerformedType::class,
             'allow_add' => true,
        ))
        ->add('Save', SubmitType::class)
    ;
    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'DefaultBundle\Entity\Bill'
        ));
    }
作为
ServicePerformedType
类,该类:

class ServicePerformedType extends AbstractType
{
  public function buildForm(FormBuilderInterface $builder, array $options)
  {
     $builder
         ->add('description', TextareaType::class, array('label' => false))
         ->add('price', TextType::class, array('label' => false))
         ->add('quantity', TextType::class, array('label' => false));
  }

}
使用此模板来呈现表单:

{{ form(form) }}
<a href="#">Add service</a>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script type="text/javascript">

    var index = 0;
    $('a').on('click', function() {

        var prototype = $('#bill_servicesPerformed').data('prototype');

        prototype = prototype.replace(/_name_/g, index.toString());

        $('#bill_servicesPerformed').html(prototype);

        index++;
    })
</script>
但是当我按下
添加服务
时,我不会得到文本
我将在这里编写我的客户原型
,而是像以前一样,与
服务性能类型
类相关的
描述
字段
数量


注意:也许还有其他方法可以自定义表单原型,但我对此很感兴趣,因此非常感谢为自定义表单原型提供了与此方法相关的解决方案的人,谢谢。

实际上,表单主题块以下划线
开头,与具有特定名称的字段相关

我的意思是,如果您的主窗体
BillType
被称为
my_form
,您将需要执行以下操作:

{% form_theme form _self %}

{% block _my_form_servicesPerformed_entry_widget %}
I WILL WRITE MY CUSTOM PROTOTYPE HERE
{% endblock %}

这种方法的问题在于它涉及到
BillType
的特定迭代。如果您在其他地方使用此表单类型并为其提供不同的名称,则必须添加一个名为
\u my\u form\u 2\u servicesPerformed\u entry\u widget

的相同块来呈现表单。您的模板存在一些问题。第一条是这一行:

prototype = prototype.replace(/_name_/g, index.toString());
正则表达式应该是
\uuuu name\uuuuu

接下来,您将检索原型,但会立即覆盖它并替换原型的HTML。我看不到任何东西会将新表单附加到现有表单的任何位置。另外,由于您只有一个文本字符串,因此
replace
不会找到任何要替换的文本
\uuuuuu name\uuuuuuu


你应该发布你的小树枝/Javascript的完整内容,这样我们才能真正看到
#bill_servicesPerformed
,以及你正在尝试做的一切。在您编写自定义原型之前,您应该让表单与标准原型一起工作,以确保您首先没有任何bug。

我必须警告您,自定义原型可能有点棘手。如果更改
FormType
字段,则需要遍历模板并进行相同的更改,否则表单将无法呈现

我喜欢做的是为特定字段创建一个自定义模板,然后对其进行适当的自定义。所以,看看你的代码,我会这样做:

  • 创建一个页面模板-用于呈现整个页面(包括表单)的模板

    {# MyBundle/Resources/views/myPage.html.twig #}
    {% extends "::base.html.twig" %}
    
    
    {# This will tell the form_theme to apply the 
       `MyBundle:form/fields/servicePerformed.html.twig` template to your "form" #}
    
    {% form_theme form with [
        'MyBundle:form/fields/servicePerformed.html.twig'
    ] %}
    
    {% block body %}
        <div>
            {{ form_start(form) }}
                {{ form_rest(form) }}
            {{ form_end(form) }}
        </div>
    {% endblock %}
    
  • 我要注意的是,在字段模板中,我传递的是原始原型
    \u self.service\u模板(form.vars.prototype)
    。通过这样做,您可以使用原始字段并在自定义原型中渲染它们。例如,此代码:

    {% macro service_template(fields) %}
        <tr>
            <td>{{ form_widget(fields.description) }}</td>
        </tr>
    {% endmacro %}
    
    {%macro服务\模板(字段)%}
    {{form_小部件(fields.description)}
    {%endmacro%}
    
    将导致类似以下呈现的prorotype的结果:

    <tr>
        <td>
            <input type="text" id="service_performed___name___description" name="service[__name__][description]"/>
        </td>
    </tr>
    
    
    
    然后可以使用javascript对其进行操作


    我希望这对你有帮助。

    举个例子,这就是我一直坚持的方式。我不知道是否有一些理由不这样做,所以要小心

    包括原型的表格:
    
    {form_label(contact_form.name,null,{'label_attr':{'class':'control label'}}}}
    {{form_小部件(contact_form.name,{'attr':{'class':'form control'}}}}}
    
    原型模板:
    
    {form_label(contact_method.name,null,{'label_attr':{'class':'col-sm-3 control label'}}}}
    {{form_小部件(contact_method.name,{'attr':{'class':'form control'}}}}}
    {form_label(contact_method.value,null,{'label_attr':{'class':'col-sm-3 control label'}}}}
    {{form_小部件(contact_method.value,{'attr':{'class':'form control'}}}}}
    

    但是要考虑的是,JavaScript需要适应这些变化。p> 您可以使用宏,看看下面的示例,即使在Symfony3中,它对我也很好。使用此示例,您还可以格式化集合原型

    看法
    {%macro小部件\原型(小部件,删除\文本)%}
    {%if widget.vars.prototype%}
    {%set form=widget.vars.prototype%}
    {%set name=widget.vars.name%}
    {%else%}
    {%set form=widget%}
    {%set name=widget.vars.full_name%}
    {%endif%}
    技巧*
    {{form_小部件(form.skill)}
    {{remove_text}}
    {{form_widget(form)}
    {%endmacro%}
    
    是的。。我也花了不少时间。幸运的是,一旦你弄明白了,就可以很容易地重用它。您只需更改字段名,就可以开始了。不管怎样,很高兴我能帮上忙:)政府对这个事实很不清楚,但你是对的。仅使用字段名+下划线(如
    \u servicesPerformed
    )根本不起作用。
    {% macro service_template(fields) %}
        <tr>
            <td>{{ form_widget(fields.description) }}</td>
        </tr>
    {% endmacro %}
    
    <tr>
        <td>
            <input type="text" id="service_performed___name___description" name="service[__name__][description]"/>
        </td>
    </tr>
    
    <div class="modal-body" id="contactMehtods" data-prototype="
        {% filter escape %}
            {{ include(':organization/partials:prototype_contact_method.html.twig', { 'contact_method': contact_form.contactMethods.vars.prototype }) }}
        {% endfilter %}">
        <div class="form-group">
            {{ form_label(contact_form.name, null, { 'label_attr': { 'class': 'control-label' }}) }}
            {{ form_widget(contact_form.name, {'attr': {'class': 'form-control'}}) }}
        </div>
    </div>
    
    <div class="form-group">
        {{ form_label(contact_method.name, null, { 'label_attr': { 'class': 'col-sm-3 control-label' }}) }}
        <div class="col-sm-9">
            {{ form_widget(contact_method.name, {'attr': {'class': 'form-control'}}) }}
        </div>
    </div>
    <div class="form-group">
        {{ form_label(contact_method.value, null, { 'label_attr': { 'class': 'col-sm-3 control-label' }}) }}
        <div class="col-sm-9">
            {{ form_widget(contact_method.value, {'attr': {'class': 'form-control'}}) }}
        </div>
    </div>
    
    {% macro widget_prototype(widget, remove_text) %}
    {% if widget.vars.prototype %}
        {% set form = widget.vars.prototype %}
        {% set name = widget.vars.name %}
    {% else %}
        {% set form = widget %}
        {% set name = widget.vars.full_name %}
    {% endif %}
    
    <div data-content="{{ name }}" class="panel panel-default">
        <div class="section row">
            <div class="col-md-12">
                <label class="field-label">Skill <span class="text-danger">*</span></label>
                <label class="field select">
                    {{ form_widget(form.skill) }}
                    <i class="arrow double"></i>                    
                </label>
            </div>
        </div>
    
        <div data-content="{{ name }}">
            <a class="btn-remove" data-related="{{ name }}">{{ remove_text }}</a>
            {{ form_widget(form) }}
        </div>
    </div>
    {% endmacro %}