symfony2 multiple nested forms prototype

≯℡__Kan透↙ 提交于 2019-11-27 09:18:10

问题


I want to include a collection type inside another collection type. It should look like this:

Using just one collection works fine, but I need to edit the prototype of the outer form, so it renders the prototype of the inner form for each line.

Any ideas how could I do that? Also what would be the best way to save

EDIT: Now I am trying to render the prototype of the nested form:

  <ul class="characteristics-container" data-prototype="{{ form_widget(form.characteristics.vars.prototype)|e }}" data-prototype-options="{{ form_widget(form.characteristics.options.vars.prototype|e ) }}">
                    {# iterate over each existing tag and render its only field: name #}
                    {% for characteristic in form.characteristics %}
                        <li>{{ form_row(characteristic.name) }}</li>

                        <div class="characteristics-options">
                            {% for opt in form.characteristics.options %}

                            {% endfor %}                     
                        </div>


                    {% endfor %}
                </ul>

It gives error in form_widget(form.characteristics.options.vars.prototype|e

Method "options" for object "Symfony\Component\Form\FormView" does not exist in 

I tried characteristics[0], and it says the key doesnt exist

Here are my form classes:

PromotionType (the base form)

$builder              
            ->add('characteristics','collection', array(
                'label'         => 'Caracteristicas',
                 'type'         => new PromotionCharacteristicType(),
                 'allow_add'    => true,
                 'allow_delete' => true,
                 'by_reference' => false
            ))

PromotionCharacteristicType

 $builder
            ->add('name',NULL, array('label'  => 'Nome'))
            ->add('options', 'collection', array(
                'type' => new PromotionCharacteristicOptionType(),
                'allow_add' => true,
                'allow_delete' => true,      
                'prototype' => true,
                'by_reference' => false,
            ))                       
        ;

PromotionCharacteristicOptionType

 $builder
            ->add('name',NULL, array('label'  => 'Nome')) 
        ;

The first level prototype, works fine.


回答1:


forms and prototype

You need to keep two prototypes from different collections. Symfony offers to store them in a data-prototype attribute of div tag, which wrap the collection. In your situation it`s very inefficient. So you can just render it by hand in empty div somethere

Example you have characters form

class CharacterType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('opts', 'collection', array(
            'type' => new OptionType(),
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            'prototype_name' => '__opt_prot__'
        ));
        $builder->add('char_desc', 'text');
    }

    public function getName()
    {
        return 'char';
    }
}

Then create form that has characters collection

$form = $this->createFormBuilder()
    ->add('chars', 'collection', array(
        'type' => new CharacterType(),
        'allow_add' => true,
        'allow_delete' => true,
        'prototype_name' => '__char_prot__'
    ))
    ->getForm();

    # example data
    $form->setData(
        array(
            'chars' => array(
                array('options' => array(), 'char_desc' => 1),
                array('options' => array(), 'char_desc' => 2),
            ),
        )
    );

and get prototypes

<div
    id="prots"
    data-prototype-opt="{{ form_widget(form.chars.vars.prototype.children['opts'].vars.prototype) | e }}"
    data-prototype-char="{{ form_widget(form.chars.vars.prototype) | e }}"
>
</div>

And then render collection like in this example or override collection_widget block

{% for char in form.chars %}
    {{ form_row(char.char_desc) }}
    <label for="">opts</label>
    {% for opt in char.opts %}
        {{ form_row(opt.text) }}
    {% endfor %}
{% endfor %}

how to save it

Use nosql database if you can. Or use EAV model for relation databases. But if you do not need to search through the options, or sort them, you can store a serialized array in the database and use the doctrine type array




回答2:


Adding to Alexey B.'s answer, I don't usually seem to need to use prototype.children['opts'] in order to be able to access the prototype for the collection. I just use prototype.<collection_name> as follows:

<div
    id="prots"
    data-prototype-opt="{{ form_widget(form.chars.vars.prototype.opts.vars.prototype) | e }}"
    data-prototype-char="{{ form_widget(form.chars.vars.prototype) | e }}"
>
</div>


来源:https://stackoverflow.com/questions/16487129/symfony2-multiple-nested-forms-prototype

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!