Reputation: 29
currently im trying to follow the example in the page of symfony:
http://symfony.com/doc/current/cookbook/form/form_collections.html
But for my own page. Things don't change a lot, instead of task and tags i have a Question and Choices (The situation is, i want to render a form that allows me to create a question an different answers so then we can play a "Multiple choice exam")
In order to do this i created the entity Pregunta (Question) and the Entity Choice. Since a question can have multiple choices but the choices correspond to only one question the relationship was mapped as Many To One.
Heres the entity code for each one. (At least the head and mapping information)
namespace Aoshido\studyBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Pregunta
*
* @ORM\Table()
* @ORM\Entity
*/
class Pregunta {
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="Contenido", type="text")
*/
private $contenido;
/**
* @var boolean
*
* @ORM\Column(name="Vof", type="boolean")
*/
private $vof;
/**
* @var string
*
* @ORM\Column(name="Respuesta", type="text",options={"default":""})
*/
private $respuesta;
/**
* @var boolean
*
* @ORM\Column(name="activo", type="boolean",options={"default":"TRUE"})
*/
private $activo;
/**
* @ORM\ManyToMany(targetEntity="Tema", inversedBy="preguntas")
* @ORM\JoinTable(name="Preguntas_Temas")
**/
private $temas;
/**
* @Assert\Type(type="Aoshido\studyBundle\Entity\Choice")
* @Assert\Valid()
* @ORM\OneToMany(targetEntity="Choice", mappedBy="pregunta",cascade={"persist"})
*/
private $choices;
public function __construct() {
$this->temas = new ArrayCollection();
$this->choices = new ArrayCollection();
}
Here's the Choice.php
namespace Aoshido\studyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Choice
*
* @ORM\Table()
* @ORM\Entity
*/
class Choice
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="contenido", type="string", length=1000)
*/
private $contenido;
/**
* @var boolean
*
* @ORM\Column(name="correcto", type="boolean")
*/
private $correcto;
/**
* @var boolean
*
* @ORM\Column(name="activo", type="boolean")
*/
private $activo;
/**
* @ORM\ManyToOne(targetEntity="Pregunta", inversedBy="choices")
* @ORM\JoinColumn(name="idPregunta", referencedColumnName="id")
*/
protected $pregunta;
Now, according to the example, when it comes to embedding forms you need to create a type (for Questions), and inside that type create a type for the other entity (for choices). So i Did
<?php
namespace Aoshido\studyBundle\form;
use Aoshido\studyBundle\form\ChoiceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class PreguntaType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('contenido');
$builder->add('vof');
$builder->add('respuesta');
$builder->add('choices', 'collection', array(
'type' => new ChoiceType(),
));
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Aoshido\studyBundle\Entity\Pregunta',
));
}
public function getName() {
return 'pregunta';
}
}
and
<?php
namespace Aoshido\studyBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ChoiceType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('contenido');
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'Aoshido\studyBundle\Entity\Choice',
));
}
public function getName() {
return 'choice';
}
}
After that if i followed the example, added 2 choices, rendered them, all seemed fine until that point.
The problem came when i wanted to Dynamically add choices using the prototype and such. First thing i did was add the 'allow_add => true' on preguntas type
$builder->add('choices', 'collection', array(
'type' => new ChoiceType(),
'allow_add' => true,
));
after that i just copied and adapted the Javascript code to allow it to add multiples choices, but after that everytime i try to refresh the page i get this error
Variable "expanded" does not exist in BraincraftedBootstrapBundle:Form:bootstrap.html.twig at line 173
This is my twig
{% extends "AoshidostudyBundle:ABM:abmPreguntas.html.twig" %}
{% block form %}
<div class="panel panel-info">
<div class="panel-heading">Agregar preguntas</div>
<div class="panel-body">
<div class="form-group">
{{ form_start(form) }}
{{ form_row(form.contenido) }}
{{ form_row(form.respuesta) }}
<ul class="choice" data-prototype="{{ form_widget(form.choices.vars.prototype)|e }}">
{% for choice in form.choices %}
<li>
{{ form_row(choice) }}
</li>
{% endfor %}
</ul>
<a href="#" id="add-another-choice">Add another choice</a>
{{ form_end(form) }}
</div>
</div>
</div>
<script type="text/javascript">
var $collectionHolder;
// setup an "add a tag" link
var $addTagLink = $('<a href="#" class="add_tag_link">Add a tag</a>');
var $newLinkLi = $('<li></li>').append($addTagLink);
jQuery(document).ready(function () {
// Get the ul that holds the collection of tags
$collectionHolder = $('ul.choice');
// add the "add a tag" anchor and li to the tags ul
$collectionHolder.append($newLinkLi);
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$addTagLink.on('click', function (e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a new tag form (see next code block)
addTagForm($collectionHolder, $newLinkLi);
});
});
function addTagForm($collectionHolder, $newLinkLi) {
// Get the data-prototype explained earlier
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
}
</script>
{%endblock%}
And the bit of the controller
$pregunta = new Pregunta();
$form = $this->createForm(new PreguntaType(), $pregunta, array(
'action' => $this->generateUrl('preguntas_ABM'),
'method' => 'POST',
));
return $this->render('AoshidostudyBundle:ABM:newForm.html.twig', array(
'form' => $form->createView(),
'paginas' => $pagination,
'cantidad' => $cant,
));
I'm using
Upvotes: 2
Views: 1311
Reputation: 193
I'd add a comment but my reputation is not enough. Did you check the docs for the correct Symfony version? You link to the current Symfony docs (which is, as of now 2.6) but you are using version 2.3.1.
Try upgrading to the lastest version and see you find the same error then.
Also, I see you are using BraincraftedBootstrapBundle. The docs are for a vanilla Symfony installation. Did you check their documentation?
http://bootstrap.braincrafted.com/playground/forms.html#inlinesub
That looks like what you are trying to achieve. A small code snippet from their page to dynamically add items using an inline form:
$this->createFormBuilder(array())
->add('repcol', 'bootstrap_collection', array(
'type' => 'repeated',
'allow_add' => true,
'allow_delete' => true,
'sub_widget_col' => 9,
'button_col' => 3,
'prototype_name' => 'inlinep',
'options' => array(
'type' => 'text',
'attr' => array('style' => 'inline')
)
))
->getForm();
Upvotes: 1