19

我想在自定义 Symfony 2 表单字段类型扩展中使用 javascript。所以,我有这样的 Twig 扩展模板:

{% block some_widget %}
    <input ... />

    <script src="some.js"></script>
    <link href="some.css" />
{% endblock %}

但我只想在我的 HTML 中使用这些脚本和链接标签一次,最好是在头标签中,而不需要修改基本模板。我尝试扩展 Twig 块,但我无法访问表单模板中的操作模板块。或者可能是这样的:

{# widget tempate #}
{% block some_widget %}
    <input ... />

    {{ use_javascript('some.js') }}
    {{ use_css('some.css') }}
{% endblock %}

{# main action template #}
...
<head>
{{ dump_javascripts() }}
{{ dump_css() }}
</head>
...

如何用 Symfony 2 Forms + Twig 做到这一点?

PS对不起我的英语不好。

4

5 回答 5

10

我必须编写一个需要 javascript 的自包含表单小部件,我能够通过event_dispatcher侦听kernel.response将 javascript 附加到Symfony\Component\HttpFoundation\Response. 这是我的表单类型的片段:

<?php

namespace AcmeBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;

class AcmeFileType extends AbstractType{

  private $twig;
  private $dispatcher;

  public function __construct(\Twig_Environment $twig, EventDispatcherInterface $dispatcher){
    $this->twig = $twig;
    $this->dispatcher = $dispatcher;
  }

  public function buildView(FormView $view, FormInterface $form, array $options){

    $javascriptContent = $this->twig->render('AcmeBundle:Form:AcmeFileType.js.twig', array());

    $this->dispatcher->addListener('kernel.response', function($event) use ($javascriptContent) {

      $response = $event->getResponse();
      $content = $response->getContent();
      // finding position of </body> tag to add content before the end of the tag
      $pos = strripos($content, '</body>');
      $content = substr($content, 0, $pos).$javascriptContent.substr($content, $pos);

      $response->setContent($content);
      $event->setResponse($response);
    });

  }

  ... 

当您在 services.yml 中定义表单类型时,它看起来像这样:

acme.form.acme_file_type:
    class: AcmeBundle\Form\AcmeFileType
    arguments:
        - @twig
        - @event_dispatcher
    tags:
        - { name: form.type, alias: acmefile }

所以现在,每次您使用 javascript 构建表单时acmefile,都会将其附加到<body>. 尽管此解决方案不会阻止javascript多次出现,但您应该可以轻松地对其进行改进以满足您的需求。

如果您愿意,您也可以使用$response对象来修改标题。

于 2014-12-30T19:10:53.123 回答
1

最好的方法是提供带有 css 和脚本加载的单独模板。有了自述文件中的评论,开发人员唯一要做的就是

{% block stylesheets %}
  {{ parent() }}

  include "@MyBestBundle/Resources/view/styles.html.twig"

{% endblock %}

或者尝试使用 DI 拦截表单渲染并添加资产。但如果可能的话,它更难做到。

于 2012-07-03T11:51:19.710 回答
1

我的做法是创建一个自定义的 twig 扩展,在其中我将 JS 添加到缓冲区并在表单呈现期间,然后将其转储到我的布局中。

像这样的东西:

<?php

namespace AppBundle\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class WysiwygExtension extends AbstractExtension
{
    /**
     * @var array
     *
     * A pool of elements IDs for Wysiwyg binding.
     */
    private $wysiwygElements = [];

    /**
     * {@inheritdoc}
     */
    public function getFunctions()
    {
        return array(
            new TwigFunction('addWysiwygBinding', [$this, 'addWysiwygBinding']),
            new TwigFunction('popWysiwygBindings', [$this, 'popWysiwygBindings']),
        );
    }

    public function addWysiwygBinding(string $id): void
    {
        $this->wysiwyglements[] = $id;
    }

    public function popWysiwygBindings(): array
    {
        $elements = array_unique($this->wysiwygElements);

        $this->wysiwygElements = [];

        return $elements;
    }
}

然后form-fields.html.twig

...
{% block wysiwyg_widget %}
{% apply spaceless %}
    {{ form_widget(form) }}
    {% do addWysiwygBinding(id) %}
{% endapply %}
{% endblock %}
...

然后layout.html.twig

<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>
    ...

        {% set ids = popWysiwygBindings() %}

        {% if ids is not empty %}
            {% javascripts
                'bundles/admin/plugins/wysiwyg_1.js'
                'bundles/admin/plugins/wysiwyg_2.js'
            %}
                <script type="text/javascript" src="{{ asset_url }}"></script>
            {% endjavascripts %}
        {% endif %}

        {% for id in ids %}
            {{ include('_wysiwyg.html.twig', { id: id }) }}
        {% endfor %}
  </body>
</html>
于 2020-05-17T11:50:39.823 回答
0

这就是我使用它的方式。希望它是你正在寻找的。

base.html.twig

<head>
   {% block stylesheets %}
       css...
   {% endblock %}
</head>

foo.html.twig

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

{% block stylesheets %}
   {{ parent() }}

   css that you need in foo.html.twig

{% endblock %}
于 2012-04-08T21:17:28.117 回答
0

我发现许多人在其他情况下使用了一些“肮脏”的方法。我们在客户端检查脚本的加载。如果我们有一个 zlkladr.js 文件,它有一个全局对象“zlkladr”

{% block our_widget %}
{% spaceless %}
  ...
  <script>
    // We must load the script only once, even if many widgets on form
    if ( !window.zlkladr ) {
      document.write('<script src="{{ asset('bundles/kladr/js/zlkladr.js') }}"></sc'+'ript>');
    }
  </script>
{% endspaceless %}
{% endblock %}
于 2015-08-22T15:07:29.217 回答