【问题标题】:Creating a 'Ajaxified' Form Field Type创建“Ajaxified”表单字段类型
【发布时间】:2016-11-29 08:10:57
【问题描述】:

在我的应用程序中,我有几个带有许多选项的表单字段。我遇到的问题类似于this question:在每次页面加载时获取和解析所有选项的成本很高(Twig 一遍又一遍地呈现所有选项,而没有客户端缓存可能)。这个问题使我创建了一种通过 AJAX 将选项发送到浏览器的方法。相当简单的方法:

  1. 通过 AJAX 获取所有选项(键值)(例如通过获取 /countries.json)并尽可能缓存。 (在这种情况下,国名不太可能经常更改)
  2. 使用 selectize、select2 或类似插件将选项插入 DOM。
  3. 享受更快的表单:-)

为了防止 Symfony 查询所有选项(不是必需的:它们是通过 AJAX 加载的),我在加载表单时添加了 setMaxResults(0)QueryBuilder(通过控制器添加选项)。是的,那是杂牌。提交表单时,它仍然会执行查询,因为它必须验证所选选项是否存在(并检查约束)。

我想创建一个custom Form Field Type,将这个功能添加到当前的EntityType:在呈现表单时不要加载选项,但仍然检查所选选项是否存在。我发现 many examplesdynamically modifying a form 相关,但我还没有找到与修改一个表单字段相关的示例,与它的父表单无关。

如何创建这样的表单字段类型?什么是好的起点?扩展EntityTypeChoiceType 或其他方法?

我已经在使用 Symfony 3.1,所以使用 lazy loading of form choices(Symfony 3.2 中的新功能)不会有问题。不确定这个新功能是否与我的问题有关。

【问题讨论】:

标签: ajax symfony symfony-forms


【解决方案1】:

带有 Ajax 控制器选项的自动完成对我来说看起来不错,但这是另一个(可能更快?)选项:通过 hinclude 呈现您的表单。

hinclude 是一个 JS 库,用于“延迟”加载页面的某些部分,Ajax 认为。 Symfony 提供集成支持 (official documentation)。

你如何使用它:

  • 将表单渲染移动到另一个控制器动作,我们称之为formAction
  • 在您的页面上包含 hinclude.js(参见官方 Github)
  • 使用此代码呈现您的表单:

    {{ render_hinclude(controller('...::form'), {'default': 'Loading...'}) }}

  • 您可能希望将表单处理保留在原始控制器操作中,因此修改生成表单的“操作”,如下所示:

    $form = $this->createForm(new FormType(), $obj, array('action' => $this->generateUrl('original_form_action')));

【讨论】:

    【解决方案2】:

    我写了一个包 (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());
          }
      }
      
    • 如何用缓存的内容填充表单域:

    这是你自己的逻辑,我建议:创建一个只返回(作为 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 结果放在您的选择字段中。

    如果您使用的是 Select2 之类的东西: 您的控制器还可以将选项作为 JSONReponse() 返回,然后您可以直接从 select2 ajax 选项加载此 JSON(请参阅捆绑文档,这就是我使用它的方式)。

    在 Form::PRE_SUBMIT 事件中获取提交的选项(如果您使用表单进行编辑,也可以是 PRE_SET_DATA),并将这些选项重新注入到字段中。

    【讨论】:

      【解决方案3】:

      考虑到您的用例,最好的方法是使用自动完成功能。这是我一直在使用的Symfony bundle,它很棒。根据我的情况,我做了一些覆盖它的 javascript(自动完成器)来增强一些功能。

      【讨论】:

      • 感谢您的建议,我可以使用该捆绑包作为灵感。我不想要服务器端搜索处理,因为客户端搜索要快得多。我也不喜欢他们的控制器实现,因为它使用 Twig 来呈现 JSON 输出。为什么?!
      • 是的,我没有使用 twig 来渲染 json,而是在控制器中编写了返回结果的JsonResponse。无需为 json 输出渲染树枝。
      • 我不确定这样的捆绑包是否有用 - 只需将选择的库添加到您的页面 + 初始化代码,在这里您可以使用“普通”实体类型。然后确实为了提高性能,您必须转到“Ajax”选项来加载您的条目。
      • 我也找到了这个包:github.com/Alsatian67/FormBundle。这看起来正是我想要的。
      猜你喜欢
      • 2014-04-14
      • 1970-01-01
      • 2016-05-15
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      • 2017-08-10
      相关资源
      最近更新 更多