创建 'Ajaxified' 表单字段类型
Creating a 'Ajaxified' Form Field Type
在我的应用程序中,我有几个带有许多选项的表单域。我遇到的问题类似于 this question:在每次页面加载时获取和解析所有选项的成本很高(Twig 一遍又一遍地呈现所有选项,而客户端不可能缓存)。这个问题让我创造了一种通过 AJAX 将选项发送到浏览器的方法。相当简单的方法:
- 通过AJAX获取所有选项(键值)(例如通过获取/countries.json)并尽可能缓存。 (在这种情况下,国家名称不太可能经常更改)
- 使用 selectize、select2 或类似插件将选项插入 DOM。
- 享受更快的表单:-)
为了防止 Symfony 查询所有选项(没有必要:它们通过 AJAX 加载)我在加载表单时将 setMaxResults(0)
添加到 QueryBuilder
(通过添加通过控制器选择)。是的,那是kludge。提交表单时它仍会执行查询,因为它必须验证所选选项是否存在(并检查约束)。
我想创建一个 custom Form Field Type that adds this functionality to the current EntityType
: don't load the options while rendering the form, but still check if the selected option exists. I found many examples related to dynamically modifying a form,但我还没有找到与只修改一个表单字段相关的示例,而与它的父表单无关。
如何创建这样的表单字段类型?什么是好的起点?扩展 EntityType
、ChoiceType
或其他方法?
我已经在使用 Symfony 3.1,所以使用 lazy loading of form choices(Symfony 3.2 中的新功能)不会有问题。不确定这个新功能是否与我的问题有关。
考虑到您的用例,最好的方法是使用自动完成。这是我一直在使用的 Symfony bundle,它很棒。根据我的情况,我做了一些覆盖它的javascript(自动完成器)以增强一些功能。
带有 Ajax 控制器选项的自动完成对我来说很不错,但这是另一个(可能更快?)选项:通过 hiinclude 呈现您的表单。
hinclude is a JS library used to "defer" load of parts of a page, thought Ajax. Symfony comes with integrated support (official documentation).
如何使用它:
- 将您的表单渲染移动到另一个控制器操作,我们称之为
formAction
- 在您的页面上包含 hinclude.js(参见官方 Github)
使用此代码呈现您的表单:
{{ render_hinclude(控制器('...::form'), {'default': 'Loading...'}) }}
您可能希望在原始控制器操作中保留表单处理,因此修改生成表单的 "action" 如下:
$form = $this->createForm(new FormType(), $obj, array( 'action' => $this->generateUrl('original_form_action')));
我写了一个包 (Alsatian/FormBundle),它在服务器端做你想做的事。
How to avoid loading each entities by each form rendering :
abstract class AbstractExtensibleChoicesType extends AbstractRoutableType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefault('choices',array());
}
}
如何使用缓存的内容填充表单字段:
那是你自己的逻辑,我建议:创建一个只有 returns(如 HTML)的控制器:
<option value="1">Option 1</option>
<option value="2">Option 2</option>
在控制器中设置 Maxage :
/*
* @Route(...)
* @Cache(maxage=64000)
*/
public function getOptionsAction(Request $request) // Home
{
$choices = $this->getDoctrine()->getManager()->getRepository //....
return $this->render(/*...*/);
}
使用 javascript 加载此 url 并将 html 结果放入您的 select 字段。
如果您使用类似 Select2 的东西:
您的控制器还可以 return 作为 JSONReponse() 的选项,然后您可以直接从 select2 ajax 选项加载此 JSON(参见包文档,这就是我使用它的方式)。
在 Form::PRE_SUBMIT 事件中获取提交的选项(如果您使用表单进行编辑,也 PRE_SET_DATA),并将这些选项重新注入字段。
在我的应用程序中,我有几个带有许多选项的表单域。我遇到的问题类似于 this question:在每次页面加载时获取和解析所有选项的成本很高(Twig 一遍又一遍地呈现所有选项,而客户端不可能缓存)。这个问题让我创造了一种通过 AJAX 将选项发送到浏览器的方法。相当简单的方法:
- 通过AJAX获取所有选项(键值)(例如通过获取/countries.json)并尽可能缓存。 (在这种情况下,国家名称不太可能经常更改)
- 使用 selectize、select2 或类似插件将选项插入 DOM。
- 享受更快的表单:-)
为了防止 Symfony 查询所有选项(没有必要:它们通过 AJAX 加载)我在加载表单时将 setMaxResults(0)
添加到 QueryBuilder
(通过添加通过控制器选择)。是的,那是kludge。提交表单时它仍会执行查询,因为它必须验证所选选项是否存在(并检查约束)。
我想创建一个 custom Form Field Type that adds this functionality to the current EntityType
: don't load the options while rendering the form, but still check if the selected option exists. I found many examples related to dynamically modifying a form,但我还没有找到与只修改一个表单字段相关的示例,而与它的父表单无关。
如何创建这样的表单字段类型?什么是好的起点?扩展 EntityType
、ChoiceType
或其他方法?
我已经在使用 Symfony 3.1,所以使用 lazy loading of form choices(Symfony 3.2 中的新功能)不会有问题。不确定这个新功能是否与我的问题有关。
考虑到您的用例,最好的方法是使用自动完成。这是我一直在使用的 Symfony bundle,它很棒。根据我的情况,我做了一些覆盖它的javascript(自动完成器)以增强一些功能。
带有 Ajax 控制器选项的自动完成对我来说很不错,但这是另一个(可能更快?)选项:通过 hiinclude 呈现您的表单。
hinclude is a JS library used to "defer" load of parts of a page, thought Ajax. Symfony comes with integrated support (official documentation).
如何使用它:
- 将您的表单渲染移动到另一个控制器操作,我们称之为
formAction
- 在您的页面上包含 hinclude.js(参见官方 Github)
使用此代码呈现您的表单:
{{ render_hinclude(控制器('...::form'), {'default': 'Loading...'}) }}
您可能希望在原始控制器操作中保留表单处理,因此修改生成表单的 "action" 如下:
$form = $this->createForm(new FormType(), $obj, array( 'action' => $this->generateUrl('original_form_action')));
我写了一个包 (Alsatian/FormBundle),它在服务器端做你想做的事。
How to avoid loading each entities by each form rendering :
abstract class AbstractExtensibleChoicesType extends AbstractRoutableType { public function configureOptions(OptionsResolver $resolver) { $resolver->setDefault('choices',array()); } }
如何使用缓存的内容填充表单字段:
那是你自己的逻辑,我建议:创建一个只有 returns(如 HTML)的控制器:
<option value="1">Option 1</option>
<option value="2">Option 2</option>
在控制器中设置 Maxage :
/*
* @Route(...)
* @Cache(maxage=64000)
*/
public function getOptionsAction(Request $request) // Home
{
$choices = $this->getDoctrine()->getManager()->getRepository //....
return $this->render(/*...*/);
}
使用 javascript 加载此 url 并将 html 结果放入您的 select 字段。
如果您使用类似 Select2 的东西: 您的控制器还可以 return 作为 JSONReponse() 的选项,然后您可以直接从 select2 ajax 选项加载此 JSON(参见包文档,这就是我使用它的方式)。
在 Form::PRE_SUBMIT 事件中获取提交的选项(如果您使用表单进行编辑,也 PRE_SET_DATA),并将这些选项重新注入字段。