Форма Symfony 2, коллекция полей не отображается

#forms #collections #symfony

#формы #Коллекции #symfony

Вопрос:

Я хотел бы создать форму, которая может добавлять несколько этапов. Я создаю форму следующим образом:

//ФОРМА

  namespace RBOTryBundleFormType;

 use SymfonyComponentFormAbstractType;
 use SymfonyComponentFormFormBuilder;

 use RBOTryBundleEntityTry;

 class TryType extends AbstractType {
   public function buildForm(FormBuilder $builder, array $options)
   {
     $builder->add('etapes', 'collection', array(
        'type' => new EtapeType(), 
        'allow_add' => true,
        'allow_delete' => true,
        'prototype' => true,
        'label' => 'Etapes'
    ));
  }
  public function getName()
{
    return 'try';
}

public function getDefaultOptions(array $options)
{
    return array(
        'data_class' => 'RBOTryBundleEntityTry',
        'csrf_protection' => true,
        'csrf_field_name' => '_token',
        // a unique key to help generate the secret token
        'intention'       => 'try_item',
    );
}
 }
  

// EtapeType

 <?php

namespace RBOTryBundleFormType;

use SymfonyComponentFormAbstractType;
use SymfonyComponentFormFormBuilder;

use RBOTryBundleEntityEtape;

class EtapeType extends AbstractType {

public function buildForm(FormBuilder $builder, array $options)
{
    $builder->add('name', 'text');
}

public function getDefaultOptions(array $options)
{
    return array(
        'data_class' => 'RBOTryBundleEntityEtape',
    );
}

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

}

// Отображение в шаблоне twig

 {{ form_row(form.etapes) }}
  

Объект Try имеет свойство etapes, которое является ArrayCollection (определено в конструкторе)

Этот код не отображает ничего, кроме метки. Я что-то пропустил?

Заранее благодарю вас

Ответ №1:

Я всегда использовал form_widget для отображения встроенных форм, но я думаю, что form_row тоже будет работать нормально. Важная вещь, на которую вы должны обратить внимание, это то, имеет ли встроенный контейнер формы атрибут «data-prototype». Затем вы должны добавить скрипт на страницу, на которой вы отображаете форму. В моем случае я использую Mootools, но, полагаю, вы можете легко перевести этот скрипт в jQuery или любой другой фреймворк javascript:

Это содержимое моего js-файла (вы должны заменить «XXX» на идентификатор элемента, в котором указан атрибут «data-prototype»:

 window.addEvent( 'domready', function() {
var add = function() {
    var collectionHolder = $('XXX');
    var prototype = collectionHolder.getAttribute('data-prototype');
    form = prototype.replace(/$$name$$/g, collectionHolder.getChildren().length);
    var cont = Elements.from(form);
    collectionHolder.adopt( cont );
}
var remove = function() {
    var collectionHolder = $('XXX');
    var child = collectionHolder.getLast();
    child.dispose();
}
$$('a.add-link').addEvent('click', function(e){
    e.stop();
    add();
});
$$('a.remove-link').addEvent('click', function(e){
    e.stop();
    remove();
});
  

});

Этот скрипт очень прост и просто добавляет новые элементы или удаляет последний элемент в коллекции. Кроме того, вы должны добавить некоторый html в свое представление, чтобы иметь ссылки на добавление / удаление:

 <ul class="actions">
<li>
    <a href="#" class="add-link">
        Add
    </a>
</li>
<li>
    <a href="#" class="remove-link">
        Remove last
    </a>
    </li>
</ul>
  

Надеюсь, это поможет, я новичок в Symfony и все еще учусь, но у меня это сработало 🙂

Комментарии:

1. Фактически, имя или этапы текстового поля не отображаются. У меня просто есть метка и ничего больше! Я читал, что мне нужно добавить функцию javascript для работы с кнопкой добавления и удаления, но я сделаю это после!

Ответ №2:

Я бы сделал это таким образом:

 {% for etape in form.etapes %}
  {{ form_widget(etape.name) }}
{% endfor %}
  

Я могу ошибаться, потому что я не использую шаблоны twig. Но эта идея сработала для меня в php-шаблонах.

Ответ №3:

В PHP шаблонах..

     `<?php foreach ($form['etapes'] as $etapesField) : ?>
<?php echo $view['form']->errors($etapesField) ?>
<?php echo $view['form']->widget($etapesField) ?>
<?php endforeach; ?>`
  

Ответ №4:

Хорошо, две вещи:

1 — Обычный способ отображения вашей формы в шаблоне twig:

     {{ form_row(form) }}
  

Система шаблонов способна каскадировать (извините за приблизительный английский), что означает, что все подполя в форме будут отображаться так же, как и ее инкапсулирующая форма. Таким образом, нет необходимости отображать дочерние элементы напрямую, вызывая form.etapes .

2 — Я считаю, что ваша проблема действительно заключается в создании экземпляра. Если вы создадите свою форму таким образом:

     $form = $this->createForm(new TryType()));
  

Или даже таким образом:

     $model = new Try();
    $model->setEtapes(array());

    $form = $this->createForm(new TryType(), $model));
  

Тогда нормально, что ваша форма ничего не отображает, потому что количество отображаемых полей Etape напрямую зависит от количества экземпляров Etape, которыми вы загружаете свою модель. Если вы предоставите ему пустой массив, поля этапа не будут отображаться. Что вы должны сделать, чтобы иметь пустое единственное поле при его отображении, так это:

     $model = new Try();
    $model->setEtapes(array(new Etape())); // Empty Etape

    $form = $this->createForm(new TryType(), $model));
  

Таким образом, вы можете добавить столько полей, сколько захотите, в свой тип коллекции:

     $model = new Try();
    $model->setEtapes(array(
        new Etape('Étape 1'),
        new Etape('Étape 2'),
        ...
    ));

    $form = $this->createForm(new TryType(), $model));
  

Ответ №5:

Поскольку вы используете вспомогательную форму, сделайте это;

 $builder
    ->add(
        'etapes',
        'collection',
        array(
            'type'          => new EtapeType(),
            'allow_add'     => true,
            'allow_delete'  => true,
        )
    )
    ->getForm()
;
  

И то, как вы отображаете в twig, на самом деле не имеет значения. Это зависит от того, что вы хотите.
form_row, form_widget все должно работать правильно.