Symfony Form Event 根据选中表动态更新Choice字段选项实现方案
Symfony 表单表字段联动列字段实现方案
疑问1解答
你需要结合FormEvents::POST_SUBMIT事件+前端AJAX实现无提交实时更新。之前POST_SUBMIT未触发是因为没有主动提交表单请求,服务端事件只有在收到表单提交请求时才会执行。
疑问2解答
Symfony官方示例的AJAX方案就是标准实现方式。因为表单类是服务端代码,运行在页面渲染阶段,用户在浏览器端选择表名的操作如果不发起请求,服务端无法感知选中值,自然没法动态修改列选项。
完整实现代码
1. 修改表单类代码
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\AbstractType; use Doctrine\DBAL\Connection; use Twig\Environment as TwigEnvironment; class SearchReplaceType extends AbstractType { private $_tableColumns = []; private $twig; private $connection; public function __construct(TwigEnvironment $twig, Connection $connection) { $this->twig = $twig; $this->connection = $connection; } public function buildForm(FormBuilderInterface $builder, array $options): void { $schemaManager = $this->connection->getSchemaManager(); $tables = $schemaManager->listTables(); $tableNames = []; foreach($tables as $table) { $tableName = $table->getName(); $tableNames[$tableName] = $tableName; foreach($table->getColumns() as $column) { $this->_tableColumns[$tableName][] = $column->getName(); } } $builder ->add('table', ChoiceType::class, [ 'placeholder' => 'Test', 'choices' => $tableNames ]) // 处理初始加载/编辑场景下的列选项生成 ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $form = $event->getForm(); $data = $event->getData(); $selectedTable = $data ? $data->getTable() : null; $columnChoices = []; if ($selectedTable && isset($this->_tableColumns[$selectedTable])) { $columnChoices = array_combine($this->_tableColumns[$selectedTable], $this->_tableColumns[$selectedTable]); } $form->add('column', ChoiceType::class, [ 'placeholder' => 'Please select a column', 'choices' => $columnChoices ]); }) // 处理表字段变更后的列选项生成 ->get('table')->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) { $form = $event->getForm()->getParent(); $selectedTable = $event->getForm()->getData(); $columnChoices = []; if ($selectedTable && isset($this->_tableColumns[$selectedTable])) { $columnChoices = array_combine($this->_tableColumns[$selectedTable], $this->_tableColumns[$selectedTable]); } $form->add('column', ChoiceType::class, [ 'placeholder' => 'Please select a column', 'choices' => $columnChoices ]); }); $builder ->add('search', TextType::class) ->add('replace', TextType::class) ->add('submit', SubmitType::class) ; } }
2. 新增控制器AJAX处理方法
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Form\FormFactoryInterface; class FormController extends AbstractController { /** * @Route("/get-table-columns", name="get_table_columns") */ public function getTableColumns(Request $request, FormFactoryInterface $formFactory) { $form = $formFactory->create(SearchReplaceType::class); $form->handleRequest($request); return $this->render('form/column_field.html.twig', [ 'columnField' => $form->get('column')->createView() ]); } }
3. 新增列字段渲染模板 templates/form/column_field.html.twig
{{ form_widget(columnField) }}
4. 前端交互代码
const tableSelect = document.querySelector('#search_replace_table'); const columnContainer = document.querySelector('#search_replace_column').parentNode; tableSelect.addEventListener('change', function () { const form = this.closest('form'); const formData = new FormData(form); fetch('/get-table-columns', { method: 'POST', body: formData }) .then(res => res.text()) .then(columnHtml => { columnContainer.innerHTML = columnHtml; }); });
注意:如果自定义了表单的name属性,需要对应修改代码中字段选择器的id前缀,默认前缀为表单类名的蛇形写法
search_replace。
内容的提问来源于stack exchange,提问作者ShibeSon
相关产品推荐
相关产品推荐

