2

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" ).

enter image description here

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 .

enter image description here

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 %}
Community
  • 1
  • 1
Charles-Antoine Fournel
  • 1,713
  • 1
  • 25
  • 37

0 Answers0