Exactly the same problem as this question :
Dropdown Ajax onchange SonataAdminBundle Symfony2 Issue
when i select "value 1" dropdown, the form send an ajax request to my curstom CRUD controller which returns values which appends my second dropdown ( "id de l'element" ).
Everything works fine, in fact, but when i want to submit all the form to create my new object, sonata throws an error, and all my previous selected values are gone .
After digging in the generated html code, i confirm that my ajax request fills correctly the second select ( "id de l'element" ) which is used to display the dropdown.
but sonata doesn't seems to get the correct values .
any ideas ?
EDITED :
I made a small trick but it's really casual.
i filled the possible choices in my formMapper with an array of 2000 index (made with a simple loop )
since i'm only need integer key , it's work but it's not generic and it takes a lot of time for the dom to generate the 2000 options in my select.
i can't imagine that sonata developer didn't make their bundle usable with ajax request .....
My entity
namespace myapp\AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* statistics
*
* @ORM\Table()
* @ORM\Entity
*/
class Statistics
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="firstValue", type="string", length=255)
*/
private $firstValue;
/**
* @var string
*
* @ORM\Column(name="filter1", type="string")
*/
private $filter1;
/**
* @var string
*
* @ORM\Column(name="secondValue", type="string", length=255)
*/
private $secondValue;
/**
* @var string
*
* @ORM\Column(name="filter2", type="string", length=255)
*/
private $filter2;
/**
* @var string
*
* @ORM\Column(name="periodicity", type="string", length=255)
*/
private $periodicity;
here is my statistics admin class :
class statisticsAdmin extends Admin
{
protected $baseRouteName = 'stats';
protected $baseRoutePattern = 'stats';
private $em;
private $bundles;
private $entities;
private $app;
public $filter1Values;
public $filter2Values;
public function getTemplate($name)
{
if ( $name == "edit" )
return 'bonkAppBundle:Admin:base_edit.html.twig' ;
return parent::getTemplate($name);
}
/**
* Récupères l'ensemble des entités disponible pour le projet
* en cours.
*
* On fait établit un filtre pour éviter que le bundle FOSUser
* soit pris en compte (il est inclus depuis l'entiti User
*
* les données collectés sont enregistrés dans une variable de class
* $this->bundles
* @return null
*/
public function getAllEntities()
{
$this->em = $this->modelManager->getEntityManager('bonk\AppBundle\Entity\Statistics');
$this->bundles = $this->em->getConfiguration()->getMetadataDriverImpl()->getAllClassNames();
$this->app = 'bonk';
foreach ( $this->bundles as $bundle )
{
$temp = explode ( '\\', $bundle );
if ( $temp[0] == 'bonk' ){
$class = $this->em->getClassMetadata( $temp[0].$temp[1].":".$temp[3] );
$associations = $class->getAssociationNames();
//foreach ( $class->fieldMappings as $field )
// $this->entities[$temp[0].$temp[1].":".$temp[3]][$temp[0].$temp[1].":".$temp[3].":".$field['fieldName']] = $field['fieldName'] ;
// on ajoute les relations de l'entite . We also add associations for the given entity class
foreach ( $associations as $association ){
$AssociatedEntity = explode ( "\\", $class->getAssociationTargetClass( $association ) );
$this->entities[$temp[0].$temp[1].":".$temp[3]][$AssociatedEntity[0].$AssociatedEntity[1].":".$AssociatedEntity[3]] = $association ;
}
}
}
}
protected function configureFormFields(FormMapper $formMapper)
{
$this->getAllEntities();
$temp = array();
//for ( $a = 1; $a < 2000 ; $a++ )
// $temp[$a] = "a";
$formMapper
->with('General')
->add('name', null, array ( 'label' => 'Titre') )
->add('firstValue', 'choice', array ( 'label' => 'Valeur 1', 'choices' => $this->entities ) )
->add('filter1' , 'choice' , array ( 'choices' => array('all' => 'Tout') ) )
->add('secondValue','choice', array ( 'label' => 'Valeur 2', 'choices' => $this->entities ) )
->add('filter2' , 'choice' , array ( 'choices' => array('all' => 'Tout') ) )
->add('periodicity','choice', array ( 'label' => 'Durée' , 'choices' => array(
'1 hour' => '1 Heure',
'1 day' => '1 Jour',
'1 week' => '1 Semaine',
'1 month' => '1 Mois',
'3 months' => '1 Trimestre',
'6 months' => '1 Semestre',
'1 year' => '1 Annee',
'2 year' => '2 Annees' ) ) )
->end()
;
}
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
->addIdentifier('name', null, array ( 'label' => 'Titre') )
->add('firstValue', null, array ( 'label' => 'Valeur 1') )
->add('filter1', null, array ( 'label' => 'filtre 1') )
->add('secondValue', null, array ( 'label' => 'Valeur 2') )
->add('filter2', null, array ( 'label' => 'filtre 2') )
->add('periodicity', null, array ( 'label' => 'Durée') )
->add('_action', 'actions', array(
'actions' => array(
'Clone' => array('template' => 'bonkAppBundle:CRUD:stat.html.twig'),
'edit' => array(),
'delete' => array(),
)
))
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'error_mapping' => array(
'test' => 'filter1Ajax',
),
));
}
/**
* Ajoute une route pour l'admin
*
* La nouvelle vue sera disponible par la route spécifiée dans
* $collection par la méthode "add"
*/
protected function configureRoutes( RouteCollection $collection )
{
$collection->add('stat', $this->getRouterIdParameter().'/stat');
}
then my javascript inside my custom overriding of base_edit.html.twig :
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
<script src="{{ path('fos_js_routing_js', {"callback": "fos.Router.setData"}) }}"></script>
<script type="text/javascript" src="{{ asset( 'public/js/chosen.jquery.min.js' ) }}"></script>
<script type="text/javascript">
$(document).ready(function(){
var firstValue = $("#{{ admin.uniqId }}_firstValue");
firstValue.change(updateValues('firstValue'));
var secondValue = $("#{{ admin.uniqId }}_secondValue");
secondValue.change(updateValues('secondValue', true ));
function updateValues(value, secondValue = false){
return function () {
if ( secondValue == false ){
var tagId = $("#{{ admin.uniqId }}_firstValue option:selected").val();
var filter1 = $("#{{ admin.uniqId }}_filter1");
}else{
var tagId = $("#{{ admin.uniqId }}_secondValue option:selected").val();
var filter1 = $("#{{ admin.uniqId }}_filter2");
}
filter1.empty();
filter1.trigger("chosen:updated");
var locale = '{{ app.request.get('_locale') }}';
var objectId = '{{ admin.id(object) }}'
$.ajax
({
type: 'POST',
url : Routing.generate('myapp_admin_get_values_from_entities', { '_locale': locale, 'tagId': tagId, _sonata_admin: 'myapp.app.admin.stats', id: objectId }) ,
data: tagId,
cache: false,
error:function ( xhr, ajaxOptions, thrownError )
{
alert(xhr.status + " " + thrownError);
},
success:function( html )
{
filter1.empty();
filter1.append(html);
filter1.trigger("chosen:updated");
filter1.val('option:first').attr('selected', true );
}
});
};
}
});
</script>
{% endblock %}