Using Symfony2.3.4 and PHP5.6.3
People, I've been looking for this issue for a while now and yes, I've found some similar ones and even found this in the Cookbook.
Now you'd say, "This guy is pretty slow", bingo, I am. Please help me out because I can't seem to get this or any other example I've encountered to help me in my own problem.
What I need is to populate a select field when the user selects an item from another select field. All this happens in a standard-CRUDgenerated-Symfony2 form. Both selects stand for an entity collection each(Zone and UEB), being Zone the independent one.
Community: Stop talking and give me the code!
Me: OK, here is what I have so far:
//ReferenceController.php
public function newAction() {
$entity = new Reference();
$form = $this->createCreateForm($entity);
return $this->render('CCBundle:Reference:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
public function createAction(Request $request) {
$entity = new Reference();
$form = $this->createCreateForm($entity);
$form->bind($request);
/*
var_dump($form->get('UEB')->getData());
var_dump($form->get('UEB')->getNormData());
var_dump($form->get('UEB')->getViewData());
die();
*/
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('reference_show', array('id' => $entity->getId())));
}
return $this->render('CCBundle:Reference:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
private function createCreateForm(Reference $entity) {
$form = $this->createForm(new ReferenceType(), $entity, array(
'action' => $this->generateUrl('reference_create'),
'method' => 'POST',
));
return $form;
}
And
//ReferenceType.php
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('suffix')
->add('zone', null, array(
'required' => true,
))
;
//What follows is for populating UEB field accordingly,
//whether it's a "createForm" or an "editForm"
if ($options['data']->getId() !== null) {
$formModifier = function (FormInterface $form, Zone $zone = null) {
$UEBs = null === $zone ? array() : $zone->getUEBs();
$form->add('UEB', 'entity', array(
'required' => true,
'label' => 'UEB',
'class' => 'CCBundle:UEB',
// 'empty_value' => '',
'choices' => $UEBs,
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
$formModifier($event->getForm(), $data->getZone());
});
} else {
$formModifier = function (FormInterface $form) {
$form->add('UEB', 'entity', array(
'required' => true,
'label' => 'UEB',
'class' => 'CCBundle:UEB',
'query_builder' =>
function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->where('u.zone = :zone')
->setParameter('zone', $er->findFirstZone());
}
)
);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formModifier) {
$formModifier($event->getForm());
});
}
And
//base.js
var goalURL = "" + window.location;
if (goalURL.slice(-13) === 'reference/new' || goalURL.match(/reference\/\d+\/edit$/))
{
//case new reference
goalURL = goalURL.replace('reference/new', 'reference/update_uebs/');
//case edit reference
goalURL = goalURL.replace(/reference\/\d+\/edit/, 'reference/update_uebs/');
//this is the function run every time the "new" or "edit" view is loaded
//and every time the Zone select field is changed
var runUpdateUEBs = function() {
$.getJSON(goalURL, {id: $('#cc_ccbundle_reference_zone').val()}, function(response) {
$('#cc_ccbundle_reference_UEB').children('option').remove();
var non_selected_options = [];
var index = 0;
$.each(response, function(key, val) {
var option = $('<option selected="selected"></option>');
option.text(val);
option.val(key);
option.prop('selected', 'selected');
option.appendTo($('#cc_ccbundle_reference_UEB'));
non_selected_options[index++] = $(option);
});
var amount = non_selected_options.length;
if (amount > 1)
$.each(non_selected_options, function(key, val) {
if (amount - 1 === key)
val.attr('selected', false);
});
});
};
runUpdateUEBs();
$('#cc_ccbundle_reference_zone').bind({
change: runUpdateUEBs
});
}
And
//ReferenceController.php
//this is where "goalURL" goes
function updateUEBsAction() {
$id = $this->getRequest()->get('id');
$em = $this->getDoctrine()->getManager();
$uebs = $em->getRepository('CCBundle:UEB')->findBy(array('zone' => $id));
$ids_and_names = array();
foreach ($uebs as $u) {
$ids_and_names[$u->getId()] = $u->getName();
}
return new \Symfony\Component\HttpFoundation\Response(json_encode($ids_and_names));
}
With this I can load the UEBs corresponding the Zone being shown at the moment and every time a new Zone is selected alright, but only visually, not internally, hence: the select populates fine but when I submit the form it doesn't go through with it and outputs "This value is not valid" on the UEB field and the
var_dump($form->get('UEB')->getData());
var_dump($form->get('UEB')->getNormData());
var_dump($form->get('UEB')->getViewData());
die();
from above outputs
null
null
string <the_value_of_the_option_tag> (length=1)
I need to know how to populate the select AND the internal data to be submitted too.
Thanks for bearing with this simple explanation.
I'm listening(reading).