2012-04-04 15 views
16

Chcę używać javascript w niestandardowym rozszerzeniu typu pola formularza Symfony 2. Tak, mam Gałązka rozszerzenie szablonu takiego:Typ pola niestandardowego formularza Symfony 2: jak dodać javascript i css tylko raz?

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

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

Ale chcę mieć te znaczniki skryptów i łącza tylko raz w moim HTML, najlepiej w tagu głowy, bez modifing szablon bazowy. Próbowałem rozszerzyć bloki Twig, ale nie mam dostępu do bloków szablonów działań wewnątrz szablonu formularza. A może coś takiego:

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

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

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

Jak to zrobić z Symfony 2 Forms + Twig?

P.S. Przepraszam za mój zły angielski.

+0

Dlaczego nie chcesz zmodyfikować szablonu bazowego? To * jest * miejscem, w którym należy ustawić pliki js \ css, które chcesz zaimportować. – tamir

+2

Chcę utworzyć pakiet z rozszerzeniem widgetu, który sam się zawiera, i włączyć ten pakiet tylko raz w AppKernel.php. Co więcej, nie chcę dodawać js/css, jeśli widget nie ma zastosowania na bieżącej stronie. –

+0

To wydaje się być brakującą funkcją w Symfony (do tej pory). Może powinniśmy zainspirować się z [mediów widgetu django] (https://docs.djangoproject.com/en/dev/topics/forms/media/#assets-as-a-static-definition), które obejmuje zasoby tylko raz, jeśli widget obecny –

Odpowiedz

0

Oto jak z tego korzystam. Mam nadzieję, że tego właśnie szukasz.

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 %} 
+1

Tak, to jest zwykły sposób na regularne tempaty widoku (i ja go używam). Ale to nie działa z szablonami typu formularza. –

1

Najlepszym sposobem jest zapewnienie osobnego szablonu z css & skrypty ładowania. z uwagami w readme więc jedyną rzeczą, deweloper musi zrobić, to

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

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

{% endblock %} 

lub próbować przechwycić postać trójwymiarowa z DI i dodać aktywów. Ale trudniej to zrobić, jeśli to możliwe do zrealizowania.

6

miałem napisać samowystarczalne widget formularz, który wymaga JavaScript, udało mi się osiągnąć to, co staramy się robić poprzez event_dispatcher słuchania na kernel.response aby dołączyć JavaScript na koniec Symfony\Component\HttpFoundation\Response. Oto fragment mojego typu forma:

<?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); 
    }); 

    } 

    ... 

Podczas definiowania typ formularza w services.yml wygląda to tak:

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

Więc teraz, za każdym razem budować formę z acmefile javascript zostanie dodany do <body>. To rozwiązanie nie przeszkadza javascript od bycia obecnym wiele razy, ale powinieneś być w stanie to poprawić w celu dostosowania do twoich potrzeb.

Można także bawić się obiektem $response, aby zmodyfikować nagłówki zamiast tego, jeśli chcesz, w przypadku.

+0

Wydaje się być legit. Symfony używa podobnej sztuczki, aby załadować pasek narzędzi debugowania sieci. – MauganRa

0

Znalazłem "brudną" metodę stosowaną przez wiele osób w innych sytuacjach. Sprawdzamy ładowanie skryptu po stronie klienta. W przypadku, gdy mamy plik zlkladr.js, który ma obiekt globalny "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 %} 
Powiązane problemy