Как связать элементы формы, что бы список основывался на предыдущих значениях формы?

Работал с примитивными параметрами формы, но сейчас затык со связями.
Я думаю картинка раскрывает суть вопроса.

При выборе марки загружаются модели марки и серии марки.

5fcd01d7e7c73464830843.png

Вот некоторый код над которым я работаю.

spoiler

class ModificationType extends AbstractType
{
	public function buildForm(FormBuilderInterface $builder, array $options)
	{
		$builder
			->add("name", TextType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Наименование",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 255]),
				],
				"required" => true,
			])
			->add("alt_name", TextType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Альтернативное наименование",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 255]),
				],
				"required" => true,
			])
			->add("seo_name", TextType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "SEO Name",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 100]),
				],
				"required" => true,
			])
			->add("power_kwt", NumberType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Мощность кВт",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Positive(),
				],
				"required" => true,
			])
			->add("power_horse", NumberType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Мощность л.с.",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Positive()
				],
				"required" => true,
			])
			->add("year_from", ChoiceType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Год начала производства",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"choices" => $this->getYears(),
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 4]),
				],
				"required" => true,
			])
			->add("year_to", ChoiceType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Год завершения производства",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"choices" => $this->getYears(),
				"empty_data" => "н.в.",
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 4]),
				],
				"required" => false,
			])
			->add("brand", EntityType::class, [
				"label" => "Бренд",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"class" => Brand::class,
				"choice_label" => function ($brand) {
					return $brand->getName();
				},
				"attr" => [
					"class" => "form-control select"
				],
				"constraints" => [
					new Assert\NotBlank()
				],
				"mapped" => false
			])
            ->add("model", EntityType::class, [
				"label" => "Модель",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"class" => Model::class,
				"choice_label" => function ($brand) {
					return $brand->getName();
				},
				"attr" => [
					"id" => "choice-model",
					"class" => "form-control select"
				],
				"constraints" => [
					new Assert\NotBlank()
				]
			])
            ->add("series", EntityType::class, [
				"label" => "Серия",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"class" => Series::class,
				"choice_label" => function ($brand) {
					return $brand->getName();
				},
				"attr" => [
					"class" => "form-control select"
				],
				"constraints" => [
					new Assert\NotBlank()
				]
			]);
	}

	public function configureOptions(OptionsResolver $resolver)
	{
		$resolver->setDefaults([
			"data_class" => Modification::class,
		]);
	}

	/**
	 * @return array
	 */
	private function getYears(): array
	{
		$years = [];
		for ($i = date("Y"); $i >= 1955; $i--) {
			$years[$i] = $i;
		}
		return $years;
	}
}


<script>

      function initialize() {
          const $brand = $('#modification_brand');
          // Когда выбран бренд ...
          $brand.change(function() {
              // ... вызвать соответствуюущую форму.
              var $form = $(this).closest('form');
              // Симулировать данные формы, но включать только значение выбранного бренда.
              var data = {};

              // data[$brand.attr('name')] = $brand.val();
              // Отправить данные через AJAX по пути действия формы.
              $.ajax({
                  url : $form.attr('action'),
                  type: $form.attr('method'),
                  data : {
                      brand_id: $brand.val()
									},
                  success: function(html) {
                      // Заменить текущую позицию на поле ...
                      $('#modification_model').replaceWith(
                          // ... той, что вернулась из ответа AJAX.
                          $(html).find('#modification_model')
                      );
                      // Теперь поле позиций отображает правильные позиции.
                  }
              });
          });
      }

      $(document).ready(initialize);



Сделал всё как в доке, стоит ли говорить что это не работает?
Очевидно, что не понимаю как подгрузить частично форму с уже наполненными данными моделей марки.

Самое печальное, что смотрю в книгу, вижу фигу
  • Вопрос задан
  • 35 просмотров
Решения вопроса 1
IgorPI
@IgorPI Автор вопроса
Всё получилось.

Хотя, не понятно, сделал всё то же самое что и раньше.
Правда, изменил HTPP method from GET to POST

Полный код формы.
spoiler

<?php

namespace App\Form;

use App\Entity\Brand;
use App\Entity\Model;
use App\Entity\Modification;
use App\Entity\Series;
use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;

class ModificationType extends AbstractType
{
	public function buildForm(FormBuilderInterface $builder, array $options)
	{
		$builder
			->add("name", TextType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Наименование",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 255]),
				],
				"required" => true,
			])
			->add("alt_name", TextType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Альтернативное наименование",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 255]),
				],
				"required" => true,
			])
			->add("seo_name", TextType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "SEO Name",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 100]),
				],
				"required" => true,
			])
			->add("power_kwt", NumberType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Мощность кВт",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Positive(),
				],
				"empty_data" => 0,
				"required" => true,
			])
			->add("power_horse", NumberType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Мощность л.с.",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Positive()
				],
				"empty_data" => 0,
				"required" => true,
			])
			->add("year_from", ChoiceType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Год начала производства",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"choices" => $this->getYears(),
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 4]),
				],
				"required" => true,
			])
			->add("year_to", ChoiceType::class, [
				"attr" => ["class" => "form-control"],
				"label" => "Год завершения производства",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"choices" => $this->getYears(),
				"empty_data" => "н.в.",
				"constraints" => [
					new Assert\NotBlank(),
					new Assert\Length(["max" => 4]),
				],
				"required" => false,
			])
			->add("brand", EntityType::class, [
				"label" => "Бренд",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"class" => Brand::class,
				"choice_label" => function ($brand) {
					return $brand->getName();
				},
				"attr" => [
					"class" => "form-control select"
				],
				"constraints" => [
					new Assert\NotBlank()
				]
			])
            ->add("model", ChoiceType::class, [
				"label" => "Модель",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"choices" => [],
				"attr" => [
					"class" => "form-control select"
				],
				"constraints" => [
					new Assert\NotBlank()
				],
				"disabled" => true
			])
            ->add("series", ChoiceType::class, [
				"label" => "Серия",
				"label_attr" => [
					"class" => "col-sm-2 form-control-label"
				],
				"choices" => [],
				"attr" => [
					"class" => "form-control select"
				],
				"constraints" => [
					new Assert\NotBlank()
				],
				"disabled" => true
			]);

		$builder->get("brand")->addEventListener(
			FormEvents::POST_SUBMIT,
			function (FormEvent $event) {
				$form = $event->getForm();

				$brand_id = $event->getData();

				$form->getParent()->add("model", EntityType::class, [
					"label_attr" => [
						"class" => "col-sm-2 form-control-label"
					],
					"attr" => [
						"class" => "form-control select"
					],
					"class" => Model::class,
					"query_builder" => function (EntityRepository $er) use ($brand_id) {
						return $er->createQueryBuilder("m")
							->andWhere("m.brand = :brand_id")
							->setParameter("brand_id", $brand_id)
							->orderBy("m.name", "ASC");
					},
					"choice_label" => function ($entity)
					{
						return $entity->getName();
					},
					"constraints" => [
						new Assert\NotBlank()
					],
					"required" => true
				]);

				$form->getParent()->add("series", EntityType::class, [
					"label_attr" => [
						"class" => "col-sm-2 form-control-label"
					],
					"attr" => [
						"class" => "form-control select"
					],
					"class" => Series::class,
					"query_builder" => function (EntityRepository $er) use ($brand_id) {
						return $er->createQueryBuilder("s")
							->andWhere("s.brand = :brand_id")
							->setParameter("brand_id", $brand_id)
							->orderBy("s.name", "ASC");
					},
					"choice_label" => function ($entity)
					{
						return $entity->getName();
					},
					"constraints" => [
						new Assert\NotBlank()
					],
					"required" => true
				]);
			}
		);
	}

	public function configureOptions(OptionsResolver $resolver)
	{
		$resolver->setDefaults([
			"data_class" => Modification::class,
		]);
	}

	/**
	 * @return array
	 */
	private function getYears(): array
	{
		$years = [];
		for ($i = date("Y"); $i >= 1955; $i--) {
			$years[$i] = $i;
		}
		return $years;
	}
}

Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы