I
I
Igor2020-12-06 19:14:15
symfony
Igor, 2020-12-06 19:14:15

How to link form elements so that the list is based on previous form values?

I worked with primitive form parameters, but now I'm stuck with connections.
I think the picture reveals the essence of the issue.

When you select a brand, models of the brand and series of the brand are loaded.

5fcd01d7e7c73464830843.png

Here is some code I am working on.

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);



I did everything as in the dock, is it worth saying that it does not work?
Obviously, I do not understand how to partially load the form with the brand model data already filled in.

The saddest thing is that I look in a book, I see a fig

Answer the question

In order to leave comments, you need to log in

1 answer(s)
I
Igor, 2020-12-06
@IgorPI

Everything worked out.
Although, it is not clear, he did everything the same as before.
True, I changed the HTTP method from GET to POST
The complete code of the form.

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;
  }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question