【问题标题】:Symfony: problem with dynamically modified formsSymfony:动态修改表单的问题
【发布时间】:2022-01-04 11:14:03
【问题描述】:

我有 2 个下拉选项:

  • 第一个服务类型
  • 第二个服务 类型是服务的一个属性,服务与解决方案有单对多关系 当您选择一个类型时,第二个选择被填充(Ajax)与选择的类型相关的服务。然后提交按钮将显示所选服务的解决方案(此“提交部分尚未实现”) 我按照symfony doc tutorial 执行此操作,但是当我在第一次选择中选择类型时,我的第二个下拉菜单消失了

这里是 mySolutionsChooseType.php:

<?php

namespace App\Form;

use App\Entity\Service;
use Doctrine\ORM\EntityManagerInterface;

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class SolutionsChooseType extends AbstractType
{

public function buildForm(FormBuilderInterface $builder, array $options): void
{

    $types = [
        "Conception et développement d'applications" => "Conception et développement d'applications",
        "Conseil et prestations en architecture des infrastructures et systèmes d'informations" =>
        "Conseil et prestations en architecture des infrastructures et systèmes d'informations",
        "Fourniture et maintenance d'applications bureautiques" => "Fourniture et maintenance d'applications bureautiques",
        "Hébergement, maintenance et diffusion d'applications métiers" => "Hébergement, maintenance et diffusion d'applications métiers",
        "Sécurité informatique" => "Sécurité informatique",
        "Services informatiques" => "Services informatiques",
        "Services collaboratifs" => "Services collaboratifs",
        "Services de communications" => "Services de communications",
        "Stockage centralisé et sécurisé de données" => "Stockage centralisé et sécurisé de données",
        "Support transversal" => "Support transversal",
    ];

    $builder
        ->add('type', ChoiceType::class, [
            'placeholder' => 'Choisissez un type de service',
            'choices' => $types,
        ]);
    };
}

如果有人可以提供帮助。提前致谢。

我的树枝视图,里面有 js 代码,供参考:

{% extends 'base.html.twig' %}

{% block title %}
Liste des Solutions par Service (et par Type)
{% endblock %}

{% block body %}
    <div class="text-center">
        <h1>Liste des Solutions</h1>
    </div>
    <div class="container">
        <div class="row">
                <h2>Voici la liste des solutions, groupées par Type de Service:</h2>
        </div>
        <div class="row">
            
            <div class="col-lg">
                {{ form_start(form, {'attr': {'id': 'solutions_choose'} }) }}    
                {{ form_end(form) }}
            </div>

            <div class="col-md-3">
                <div class="input-group">
                    <div class="input-group-append">
                        Ajouter une solution&nbsp;
                        <a href="{{ path('solution_create') }}">
                            <button class="btn btn-outline-primary" type="submit">
                                <i class="fa fa-plus"></i></button>
                        </a>
                        
                    </div>
                </div>
            </div>
        </div>
    </div>

{% endblock %}

{% block javascripts %}
    {{ parent() }}
    <script>

        $(document).ready(function() {
                    
        var type = $('#solutions_choose_type');
        type.change(function () {
            
            
            var data = $('#solutions_choose_type option:selected').val();
            $.ajax({
                url:  '/solution/ajax',
                type: 'POST',
                //type: form.attr('method'),
                data: {"type": data},
                success: function (html) {
                    // Replace current position field ...
                    $('#solutions_choose_services').replaceWith(
                        // ... with the returned one from the AJAX response.
                        $(html.responseText).find('#solutions_choose_services')
                        // Position field now displays the appropriate positions.
                    )
                }
            });
            //alert (form.attr('action'));
            console.log(data);
            //console.log(form);
        });

        });
</script>
{% endblock %}

选择的类型被变量数据正确传递(我可以通过 console.log(data); 看到)

我的解决方案控制器.php:

class SolutionController extends AbstractController
{

/**
 * @Route("/ajax", name="ajax")
 * 
 */
public function UpdateSolutions(ServiceRepository $servrepo, Request $request): Response
{
    $form = $this->createForm(SolutionsChooseType::class);
    $type = $request->request->get('type');
    // dd($type);
    $services = $servrepo->findBy([
        'Type' => $type,
    ]);
    $form->add('services', ChoiceType::class, [
        'placeholder'   => 'Choisir un service',
        'choices'       => $services,
    ]);
    return $this->renderForm("solution/SolutionsAll.html.twig", [
        'form' => $form,
    ]);
}

【问题讨论】:

  • line 33: function (FormEvent $event, EntityManagerInterface $entityManager)函数名在哪里????

标签: php ajax symfony


【解决方案1】:

这有几个部分。

让我们从控制器开始:

createForm() 方法接收三个参数:typedataoptions,因此您的行:$form = $this-&gt;createForm(SolutionsChooseType::class, $type); 应为:

$form = $this->createForm(SolutionsChooseType::class, $data, [
    'choices' => array_combine($types, $types),
]);

array_combine() 将为每个 option 分配与文本相同的 value

您可以从SolutionsChooseType 中删除'choices' =&gt; array_flip($options['data']), 行,因为您将从控制器传递它们。

或者,您可以将控制器中完成的设置移动到类型本身,将控制器传递的任何选项与您的默认值合并。

仍然是表单类型,FormEvent 回调将事件作为第一个参数传递,底层数据作为第二个参数传递,因此您有机会对其进行修改;在你的情况下,这是一个字符串。

你有两个选择:

  • 由于您要添加EntityType 字段,您可以在其中使用query_builder 选项。这将为可用于填充选项的类传递一个EntityRepository(您必须返回一个QueryBuilder,而不是choices 本身):
function (FormEvent $event) {
    $form = $event->getForm();
    $data = $event->getData();

    $form->add('services', EntityType::class, [
        'class'       => Service::class,
        'placeholder' => 'Choisissez un type de service',
        'query_builder' => function($repository) use ($data) {
            return $repository->createQueryBuilder('s')
                              ->where('u.Type = :type')
                              ->setParameter('type', $data);
        },
    ]);
}
  • EntityManager(或直接App\Repository\ServiceRepository)注入到您的父类型中,并在表单修饰符函数中使用它。您将可以访问parent scope
class SolutionsChooseType extends AbstractType
{
    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    // Code and listener setup ommited

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

        $services = $this->em->getRepository(Service::class)->findBy([
            'Type' => $data,
        ]);

        $form->add('services', EntityType::class, [
            'class'       => Service::class,
            'placeholder' => 'Choisissez un type de service',
            'choices'     => $services,
         ]);
    }
}

【讨论】:

  • 谢谢@msg,我会试试这个!
  • 好吧,我不得不承认我说的有点太快了,“选定的类型是由可变数据正确传递的”。好的,我正在视图的 js 部分中编写警报('data'),并且当我在 SolutionsChooseType.php 中编写 var_dump($data) 时,弹出窗口正确显示了所选类型,但它显示了我整个类型数组:-(所以,ajax 和我的 SolutionsChooseType.php 之间可能出了点问题...(关于 url ???)。 url 参数应该是到控制器的路由,而不是类型,对吗?(我认为与类型中的路由无关..)
  • @PierreErnould 我不确定我是否理解......你得到了choices 或整个(父)表单数据?在PRE_SET_DATA 中,您应该得到一个包含整个对象提交值的数组。如果您只需要type,则应将侦听器附加到该字段:$builder-&gt;get('type')-&gt;addEventListener(...)。此外,您的 javascript 可能发送了错误的数据,我认为您想要 var data = $(this).val();var data = $(this).children("option:selected").val();,它应该返回相同的内容。
  • 我想检索在第一个下拉列表中选择的类型;然后我使用这种类型在我的数据库中搜索具有这种类型的服务;然后我想在第二个下拉列表中注入这些服务
  • @PierreErnould 再次仔细阅读您的问题后,我发现控制器中存在问题,我已经修改了答案。由于我无法尝试,如果有任何其他错误,请告诉我。
猜你喜欢
  • 1970-01-01
  • 2017-02-19
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 2018-02-22
  • 1970-01-01
相关资源
最近更新 更多