Masalahnya adalah tidak ada yang dimuat di bidang kotamadya, itu tidak terdefinisi. Dalam kode AJAX saya mendapatkan nilai provinsi dengan baik. Tapi di kelas addMunicipioField.php tidak mengambil nilai $province, selalu nul

enter image description here

Saya mencoba membuat formulir pendaftaran di mana bagian dari bidang biasa (name, nick, password, ...) saya juga menambahkan dua bidang dependen Municipality dan Province.

Pengontrol codec:

class UserController extends Controller {

private $session;

public function __construct() {
    $this->session = new Session();
}

public function registerAction(Request $request) {

    if (is_object($this->getUser())) {
        return $this->redirect('home');
    }

    $user = new DbUsuario();

    $form = $this->createForm(RegistreUserType::class, $user);

    $form->handleRequest($request);
    if ($form->isSubmitted()) {
        if ($form->isValid()) {
            $em = $this->getDoctrine()->getManager();
            $query = $em->createQuery('SELECT u FROM BackendBundle:DbUsuario u WHERE u.email = :email OR u.nick = :nick')
                    ->setParameter('email', $form->get("email")->getData())
                    ->setParameter('nick', $form->get("nick")->getData());

            $user_isset = $query->getResult();

            if (count($user_isset) == 0) {
                $factory = $this->get("security.encoder_factory");
                $encoder = $factory->getEncoder($user);

                $password = $encoder->encodePassword($form->get("password")->getData(), $user->getSalt());

                $user->setPassword($password);
                $user->setRole("ROLE_USER");
                $user->setImagen(null);

                $em->persist($user);
                $flush = $em->flush();

                if ($flush == null) {
                    $status = "Te has registrado correctamente";
                    $this->session->getFlashBag()->add("status", $status);
                    return $this->redirect("login");
                } else {
                    $status = "No te has registrado correctamente";
                }
            } else {
                $status = "Usuario ya esta registrado.";
            }
        } else {
            $status = "No te has registrado correctamente.";
        }
        $this->session->getFlashBag()->add("status", $status);
    }
    return $this->render('AppBundle:User:register.html.twig', array(
                "form" => $form->createView() # Genera el html del formulario.
    ));
}

Entitas yang membuat formulir adalah DbUsuario, yang memiliki bidang idMunicipio.

/** @var \BackendBundle\Entity\DbMunicipios */
private $idMunicipio;

/**
 * Set idMunicipio
 * @param \BackendBundle\Entity\DbMunicipio $idMunicipio
 * @return DbUsuario
 */
public function setIdMunicipio(\BackendBundle\Entity\DbMunicipio $idMunicipio = null) {
    $this->idMunicipio = $idMunicipio;
    return $this;
}

/**
 * Get idMunicipio
 * @return \BackendBundle\Entity\DbMunicipio
 */
public function getIdMunicipio() {
    return $this->idMunicipio;
}

Kemudian Entitas Dari DbMunicipio yang terhubung dengan 'provinsi' dengan :

/** @var \BackendBundle\Entity\DbProvincia */
private $provincia;

/**@param \BackendBundle\Entity\DbProvincia $provincia
 * @return DbMunicipio
 */
public function setProvincia(\BackendBundle\Entity\DbProvincia $provincia = null){
    $this->provincia = $provincia;
    return $this;
}

// And implement this function.
public function __toString(){
    return $this->getMunicipio();
}

/**@return \BackendBundle\Entity\DbProvincia */
public function getProvincia(){
    return $this->provincia;
}

Dan Entitas DbProvincia yang hanya memiliki bidang (id (integer), slug (String) and province (String)).

Saya mendefinisikan formulir sebagai berikut:

namespace AppBundle\Form;
use ....

class RegistreUserType extends AbstractType {

public function buildForm(FormBuilderInterface $builder, array $options) {
     $factory = $builder->getFormFactory(); 

    $builder->add('nombre', TextType::class, array('label' => 'Nombre',
        'required' => 'required',
        'attr' => array('class' => 'form-nombre form-control')
    ));
    $builder->add('apellido', TextType::class, array('label' => 'Apellido',
        'required' => 'required',
        'attr' => array('class' => 'form-apellido form-control')
    ));
    $builder->add('nick', TextType::class, array('label' => 'Nick',
        'required' => 'required',
        'attr' => array('class' => 'form-nick form-control nick-input')
    ));

    $provinSubscriber = new AddProvinciaField($factory);
    $builder->addEventSubscriber($provinSubscriber);

    $muniSubscriber = new AddMunicipioField($factory);
    $builder->addEventSubscriber($muniSubscriber);

    $builder->add('email', EmailType::class, array('label' => 'Correo electrónico',
        'required' => 'required',
        'attr' => array('class' => 'form-email form-control')
    ));
    $builder->add('password', PasswordType::class, array('label' => 'Password',
        'required' => 'required',
        'attr' => array('class' => 'form-password form-control')
    ));

    $builder->add('Registrarse', SubmitType::class, array("attr" => array("class" => "form-submit btn btn-success")));

}

public function configureOptions(OptionsResolver $resolver) {
    $resolver->setDefaults(array(
        'data_class' => 'BackendBundle\Entity\DbUsuario'
    ));
}

public function getBlockPrefix() { return 'backendbundle_dbusuario'; }
}

Saya mendefinisikan dalam AppBundle \ Form \ eventListener \ AddProvinciaField kelas yang dipanggil dalam formulir:

namespace AppBundle\Form\EventListener;

use ....
use BackendBundle\Entity\DbProvincia;

class AddProvinciaField implements EventSubscriberInterface {
     private $factory;

    public function __construct(FormFactoryInterface $factory) {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents() {
        return array(
            FormEvents::PRE_SET_DATA => 'preSetData',
            FormEvents::PRE_SUBMIT     => 'preSubmit'
        );
    }

    private function addProvinciaForm($form, $provincia) {

       $form -> add('provincia', EntityType::class, array(
            'class'         => 'BackendBundle:DbProvincia',
            'label'         => 'Provincia',
            'placeholder'   => '_ Elegir _',
            'auto_initialize' => false,
            'mapped'        => false,
            'attr'=> array('class' => 'form-provincia form-control provincia-input'),
            'query_builder' => function (EntityRepository $repository) {
                $qb = $repository->createQueryBuilder('provincia');
                return $qb;
            }
        ));
    }

    public function preSetData(FormEvent $event){
        $data = $event->getData();
        $form = $event->getForm();

        if (null === $data) {return;}

        $provincia = ($data->getIdMunicipio()) ? $data->getIdMunicipio()->getProvincia() : null ;
        $this->addProvinciaForm($form, $provincia);
    }

    public function preSubmit(FormEvent $event) {
        $data = $event->getData();
        $form = $event->getForm();

        if (null === $data) { return;}

        $provincia = array_key_exists('provincia-input', $data) ? $data['provincia-input'] : null;
        $this->addProvinciaForm($form, $provincia);
    }  
}

Dan nanti saya mendefinisikan AddMunicipioField.php:

namespace AppBundle\Form\EventListener;

 use ....
 use BackendBundle\Entity\DbProvincia;


 class AddMunicipioField implements EventSubscriberInterface {
    private $factory;

    public function _construct(FormFactoryInterface $factory) {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents() {
        return array(
            FormEvents::PRE_SET_DATA => 'preSetData',
            FormEvents::PRE_SUBMIT     => 'preSubmit'
        );
    }

    private function addMunicipioForm($form, $provincia) {
        $form->add('idMunicipio', EntityType::class, array(
            'class'         => 'BackendBundle:DbMunicipio',
            'label'         => 'Municipio',
            'placeholder'   => '_ Elegir _',
            'auto_initialize' => false,
            'attr'=> array('class' => 'form-municipio form-control municipio-input'),
            'query_builder' => function (EntityRepository $repository) use ($provincia) {
            $qb = $repository->createQueryBuilder('idMunicipio')
                ->innerJoin('idMunicipio.provincia', 'provincia');
            if ($provincia instanceof DbProvincia) {
                $qb->where('idMunicipio.provincia = :provincia')
                ->setParameter('provincia', $provincia);

            } elseif (is_numeric($provincia)) {
                $qb->where('provincia.id = :provincia')
                ->setParameter('provincia', $provincia);

            } else {
                $qb->where('provincia.provincia = :provincia')
                ->setParameter('provincia', null);

            }
            return $qb;
        }
    ));
}

public function preSetData(FormEvent $event){
    $data = $event->getData();
    $form = $event->getForm();

    if (null === $data) { return; }

    $provincia = ($data->getIdMunicipio()) ? $data->getIdMunicipio()->getProvincia() : null ;
    $this->addMunicipioForm($form, $provincia);
}

public function preSubmit(FormEvent $event){
    $data = $event->getData();
    $form = $event->getForm();

    if (null === $data) { return; }

    $provincia = array_key_exists('provincia_input', $data) ? $data['provincia_input'] : null;
    $this->addMunicipioForm($form, $provincia);
}

}

Dan akhirnya permintaan AJAX:

$(document).ready(function(){
    var $form = $(this).closest('form');
    $(".provincia-input").change(function(){
        var data = { idMunicipio: $(this).val() };
        $.ajax({
            type: 'POST',
            url: $form.attr('action'),
            data: data,
            success: function(data) {
                for (var i=0, total = data.length; i < total; i++) {
                    $('.municipio-input').append('<option value="' + data[i].id + '">' + data[i].municipio + '</option>');
                }
            }
        });
    });
});

Saya menambahkan var_dump dan alert() dalam kode. Ini adalah cara keluaran.

Dalam hal ini, nilai provinsi selalu nol.

 addMunicipioField.php
 public function preSetData(FormEvent $event){
    $data = $event->getData();
    $form = $event->getForm();

    if (null === $data) {
        return;
    }

    $provincia = ($data->getIdMunicipio()) ? $data->getIdMunicipio()->getProvincia() : null ;
    var_dump('presetdata');
    var_dump($provincia);
    $this->addMunicipioForm($form, $provincia);
}

AJAX:

$(document).ready(function(){
    var $form = $(this).closest('form');
    $(".provincia-input").change(function(){
        alert($('.provincia-input').val()); // THIS IS CORRECT VALUE, INTEGER.
        var data = { idMunicipio: $(this).val() };
        $.ajax({
            type: 'POST',
            url: $form.attr('action'),
            data: data,
            success: function(data) {
                alert(data);
                alert(data.length); // THIS IS INCORRECT.
                for (var i=0, total = data.length; i < total; i++) {
                    $('.municipio-input').append('<option value="' + data[i].id + '">' + data[i].municipio + '</option>');
                }
            }
        });
    });
});

enter image description here

Sudut pandang lain Entitasnya sama. Dalam hal ini berfungsi tetapi saya harus menekan tombol kirim. Bagaimana saya bisa melakukannya tanpa menekan tombol, bahwa itu adalah perubahan otomatis?

Kelas RegistreUserType memperluas AbstractType Saya menambahkan baris berikut.

$builder -> add('provincia', EntityType::class, array(
        'class'         => 'BackendBundle:DbProvincia',
        'label'         => 'Provincia',
        'placeholder'   => '_ Elegir _',
        'auto_initialize' => false,
        'mapped'        => false,
        'attr'=> array('class' => 'form-provincia form-control provincia-input'),
        'query_builder' => function (EntityRepository $repository) {
            $qb = $repository->createQueryBuilder('provincia');
            return $qb;
        }
    ));

    $builder->add('idMunicipio', EntityType::class, array(
        'class' => 'BackendBundle:DbMunicipio',
        'label'         => 'Municipio',
        'placeholder'   => '_ Elegir _',
        'auto_initialize' => false,
        'mapped'        => false,
        'attr'=> array('class' => 'form-municipio form-control municipio-input')
    ));

    $builder->addEventSubscriber(new AddMunicipioField());

Kelas baru AddMunicpioField():

class AddMunicipioField implements EventSubscriberInterface {

public static function getSubscribedEvents() {
    return array(
        FormEvents::PRE_SUBMIT => 'preSubmit',
        FormEvents::PRE_SET_DATA => 'preSetData',
    );
}

public function preSubmit(FormEvent $event){
    $data = $event->getData();
    $this->addField($event->getForm(), $data['provincia']);
}

protected function addField(Form $form, $provincia){
    $form->add('idMunicipio', EntityType::class, array(
        'class'         => 'BackendBundle:DbMunicipio',
        'label'         => 'Municipio',
        'placeholder'   => '_ Elegir _',
        'auto_initialize' => false,
        'mapped'        => false,
        'attr'=> array('class' => 'form-municipio form-control municipio-input'),
        'query_builder' => function(EntityRepository $er) use ($provincia){
            $qb = $er->createQueryBuilder('idMunicipio')
                    ->where('idMunicipio.provincia = :provincia')
                    ->setParameter('provincia', $provincia);

            return $qb;
        }
    ));
}

Codec Ajax:

$(document).ready(function () {
$('.provincia-input').change(function () {       
    var $form = $(this).closest('form');
    var data = $('.provincia-input').serialize();
    $.ajax({
        url: $form.attr('action'),
        type: 'POST',
        data: data,
        success: function (data) {
            $('.municipio-input').replaceWith($(html).find('.municipio-input'));
        }
    });
});

});

8
Merche 12 Maret 2017, 23:37

2 jawaban

Jawaban Terbaik

Terpecahkan!!

Dalam formulir saya, saya menambahkan panggilan ke dua kelas baru:

$builder -> addEventSubscriber(new AddMunicipioFieldSubscriber('idMunicipio'));
$builder -> addEventSubscriber(new AddProvinceFieldSubscriber('idMunicipio'));

Pilihan pertama adalah provinsi, ini adalah kelasnya:

class AddProvinceFieldSubscriber implements EventSubscriberInterface {
private $propertyPathToMunicipio;

public function __construct($propertyPathToMunicipio) {
    $this->propertyPathToMunicipio = $propertyPathToMunicipio;
}

public static function getSubscribedEvents() {
    return array(
        FormEvents::PRE_SET_DATA => 'preSetData',
        FormEvents::PRE_SUBMIT   => 'preSubmit'
    );
}

private function addProvinceForm($form, $Province = null) {
    $formOptions = array(
        'class'         => 'BackendBundle:DbProvincia',
        'mapped'        => false,
        'label'         => 'Provincia',
        'attr'          => array(
            'class' => 'class_select_provincia',
        ),
    );

    if ($Province) {
        $formOptions['data'] = $Province;
    }

    $form->add('provincia', EntityType::class, $formOptions);
}

public function preSetData(FormEvent $event){
    $data = $event->getData();
    $form = $event->getForm();

    if (null === $data) {
        return;
    }

    $accessor = PropertyAccess::createPropertyAccessor();

    $municipio    = $accessor->getValue($data, $this->propertyPathToMunicipio);
    $provincia = ($municipio) ? $municipio->getIdMunicipio()->getProvincia() : null;

    $this->addProvinceForm($form, $provincia);
}

public function preSubmit(FormEvent $event){
    $form = $event->getForm();

    $this->addProvinceForm($form);
}
}

Kelas kedua adalah Municipi:

class AddMunicipioFieldSubscriber implements EventSubscriberInterface {
//put your code here

private $propertyPathToMunicipio;

public function __construct($propertyPathToMunicipio){
    $this->propertyPathToMunicipio = $propertyPathToMunicipio;
}

public static function getSubscribedEvents(){
    return array(
        FormEvents::PRE_SET_DATA  => 'preSetData',
        FormEvents::PRE_SUBMIT    => 'preSubmit'
    );
}

private function addCityForm($form, $province_id){
    $formOptions = array(
        'class'         => 'BackendBundle:DbMunicipio',
        'label'         => 'Municipio',
        'attr'          => array(
            'class' => 'class_select_municipio',
        ),
        'query_builder' => function (EntityRepository $repository) use ($province_id) {
            $qb = $repository->createQueryBuilder('municipio')
                ->innerJoin('municipio.provincia', 'provincia')
                ->where('provincia.id = :provincia')
                ->setParameter('provincia', $province_id)
            ;

            return $qb;
        }
    );

    $form->add($this->propertyPathToMunicipio, EntityType::class, $formOptions);
}

public function preSetData(FormEvent $event){
    $data = $event->getData();
    $form = $event->getForm();

    if (null === $data) {
        return;
    }

    $accessor    = PropertyAccess::createPropertyAccessor();

    $municipio        = $accessor->getValue($data, $this->propertyPathToMunicipio);
    $province_id = ($municipio) ? $municipio->getIdMunicipio()->getProvincia()->getId() : null;

    $this->addCityForm($form, $province_id);
}

public function preSubmit(FormEvent $event){
    $data = $event->getData();
    $form = $event->getForm();

    $province_id = array_key_exists('provincia', $data) ? $data['provincia'] : null;

    $this->addCityForm($form, $province_id);
} 
}

Yang dikontrol menambahkan fungsi ini:

    public function municipioTestAction(Request $request){
    $provincia_id = $request->get('provincia_id');

    $em = $this->getDoctrine()->getManager();
    $provincia = $em->getRepository('BackendBundle:DbMunicipio')->findByProvinceId($provincia_id);

    return new JsonResponse($provincia);
}

Di mana fungsi findByProvinceId, saya membuatnya sebagai repositori entitas DbMunicipio.

class DbMunicipioRepository extends EntityRepository{

public function findByProvinceId($provincia_id){

    $query = $this->getEntityManager()->createQuery("
        SELECT muni
        FROM BackendBundle:DbMunicipio muni
        LEFT JOIN muni.provincia provin
        WHERE provin.id = :provincia_id
    ")->setParameter('provincia_id', $provincia_id);

    return $query->getArrayResult();
} 
}

Dan de codec AJAX.

$(document).ready(function () {
$(".class_select_provincia").change(function(){
    var data = {
        provincia_id: $(this).val()
    };

    $.ajax({
        type: 'POST',
        url: URL+'/municipio-test',
        data: data,
        success: function(data) {

            var $muni_selector = $('.class_select_municipio');
            alert(data);
            $muni_selector.html('<option>Ciudad</option>');

            for (var i=0, total = data.length; i < total; i++) {
                $muni_selector.append('<option value="' + data[i].id + '">' + data[i].municipio + '</option>');
            }
        }
    });
});
});
0
Merche 24 Maret 2017, 00:19

Saya tidak melihat bidang atau properti yang disebut 'select_provincia' di entitas Anda, atau bentuk utama, jadi saya akan mencoba menebak, bahwa itu mungkin harus disebut 'provincia' saja, karena itu adalah nama untuk kedua properti di entitas kotamadya dan dalam bentuk pelanggan untuk kotamadya. Juga di AddMunicipioField.php Anda harus mengubah kode ini:

if ($provincia instanceof DbProvincia) {
   $qb->where('idMunicipio.provincia = :provincia')
      >setParameter('provincia', $provincia);
} 

Untuk ini:

if ($provincia instanceof DbProvincia) {
   $qb->where('idMunicipio.provincia = :provincia')
      >setParameter('provincia', $provincia->getId());
} 

Karena saat menanyakan Anda akan membandingkan provinsi dengan ID provinsi.

Lebih jauh lagi, pastikan Anda telah mengimplementasikan metode __toString() di entitas kotamadya, sehingga symfony akan tahu bagaimana mengonversi objek itu menjadi string untuk menampilkannya di daftar pilih.

Semoga ini membantu :)


Melihat bahwa Anda telah menambahkan informasi baru, saya akan memperbarui jawaban saya:

Pertama, Di AddMunicipioField.php pada dasarnya Anda masih memiliki kesalahan yang sama: kunci array akan dipanggil dengan cara yang sama seperti Anda menamai bidang Anda, dalam hal ini bukan 'provincia_input', tetapi 'provincia'. Anda dapat melihat data yang dikirimkan kepada Anda dengan memanggil "dump($data); die;" tepat sebelum Anda memeriksa apakah kunci array ada (periksa nama kunci "provincia", karena Anda dapat melihat nama tersebut cocok dengan apa yang telah Anda tentukan saat menambahkan bidang ke formulir (AddProvinciaField.php):

$form -> add('provincia', EntityType::class

Hal lain yang saya perhatikan di cuplikan js pertama yang Anda posting adalah di bagian kode ini:

$(".provincia-input").change(function(){
    var data = { idMunicipio: $(this).val() };
    $.ajax({
        type: 'POST',
        url: $form.attr('action'),
        data: data,
        success: function(data) {
            for (var i=0, total = data.length; i < total; i++) {
                $('.municipio-input').append('<option value="' + data[i].id + '">' + data[i].municipio + '</option>');
            }
        }
    });
});

Anda mengambil input dari $(".provincia-input") dan mengirimkannya sebagai nilai untuk bidang yang disebut "idMunicipio", yang menurut saya situasi Anda tidak masuk akal.


Terakhir, saya akan membahas kesalahan yang dibuat di bagian terakhir dari JS yang Anda posting:

  $(document).ready(function () {
    $('.provincia-input').change(function () {       
        var $form = $(this).closest('form');
        var data = $('.provincia-input').serialize();
        $.ajax({
            url: $form.attr('action'),
            type: 'POST',
            data: data,
            success: function (data) {
                $('.municipio-input').replaceWith($(html).find('.municipio-input'));
            }
        });
    });
  });

Pertama-tama, nama kelas tidak seharusnya digunakan untuk mengidentifikasi bidang yang Anda gunakan. Menurut definisi mereka seharusnya digunakan beberapa kali dalam dokumen dan hanya menjelaskan gaya, yang mungkin menyebabkan beberapa perilaku tak terduga saat basis kode Anda tumbuh. Harap tetapkan nilai ID yang tepat untuk input yang akan Anda tanyakan dan terutama ganti sehingga Anda dapat mengidentifikasinya dengan benar.

Kedua, silakan merujuk ke kode JS yang diposting di tutorial resmi Symfony dengan mengikuti tautan. Seperti yang Anda lihat, cara yang tepat untuk mengirim data kembali ke server bukanlah dengan mengirimkan satu-satunya properti seperti yang Anda coba lakukan di baris ini:

var data = $('.provincia-input').serialize();

Melainkan dengan mengirimkan properti sebagai bagian dari data formulir. Jadi seperti pada tutorial yang sudah saya posting, silahkan buat dulu objek data kosong:

var data = {};

Kemudian tambahkan nilai provinsi ke dalamnya:

data[$(this).attr('name')] = $(this).val();

Ketiga, bagian kode ini jelas salah:

success: function (data) {
        $('.municipio-input').replaceWith($(html).find('.municipio-input'));
}

Seperti yang Anda lihat, variabel html tidak terdefinisi di bagian kode itu. Ini tentu saja karena variabel yang seharusnya Anda gunakan dalam hal ini disebut data (respons yang Anda dapatkan dari server). Jadi tolong ubah menjadi ini:

success: function (data) {
        $('.municipio-input').replaceWith($(data).find('.municipio-input'));
}

Terakhir, jika Anda masih mempelajari SF dan pemrograman web, saya ingin menyarankan untuk mengambil pendekatan dari bawah ke atas untuk memajukan pengetahuan pemrograman Anda, karena kasus ini cukup rumit dan masalah yang mencegah kode Anda berfungsi masih memerlukan pemahaman yang lebih dalam tentang teknologi. Anda menggunakan. Saya pribadi menyarankan membaca tentang penggunaan atribut HTML, penanganan formulir Symfony, membaca tentang data apa yang tersedia untuk Anda selama setiap acara formulir Symfony dan mungkin mencoba menggunakan komponen dumper symfony lebih banyak untuk men-debug kode Anda, karena var_dump benar-benar sangat cara yang tidak efisien untuk men-debug kode SF (akan memecahkan banyak masalah untuk Anda).

3
grssn 21 Maret 2017, 14:29