我想在自定义Symfony 2表单字段类型扩展中使用javascript。所以,我有这样的Twig扩展模板:
{% block some_widget %}
<input ... />
<script src="some.js"></script>
<link href="some.css" />
{% endblock %}
但是我想在我的HTML中只使用一次这些脚本和链接标记,理想情况是在head标记中,而不需要修改基本模板。我试图扩展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执行此操作?
P.S。抱歉我的英语不好。
答案 0 :(得分:8)
我必须编写一个需要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 }
现在,每次使用acmefile
构建表单时,javascript都会附加到<body>
。此解决方案并不会阻止多次出现 ,但您应该可以轻松地根据自己的需要进行改进。
如果您愿意,也可以使用$response
对象来修改标题。
答案 1 :(得分:1)
最好的方法是使用css&amp;提供单独的模板。脚本加载。 随着readme中的注释,开发人员必须做的只是
{% block stylesheets %}
{{ parent() }}
include "@MyBestBundle/Resources/view/styles.html.twig"
{% endblock %}
或尝试使用DI拦截表单呈现并添加资产。但如果可能的话,实施起来会更加困难。
答案 2 :(得分:0)
这就是我使用它的方式。希望这是你正在寻找的。 p>
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 %}
答案 3 :(得分: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 %}
答案 4 :(得分:0)
我的工作方式是创建一个自定义的树枝扩展名,在其中将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>