2016-07-25 19 views
5

In meiner Anwendung habe ich ein paar Formularfelder mit vielen Optionen. Das Problem, das ich erlebt habe, ist ähnlich wie this question: das Holen und Analysieren aller Optionen bei jedem Seitenladen ist teuer (Twig rendert alle Optionen immer und immer wieder, während kein clientseitiges Caching möglich ist). Dieses Problem hat mich dazu veranlasst, eine Möglichkeit zu schaffen, die Optionen über AJAX an den Browser zu senden. Ziemlich einfache Methode:Erstellen eines 'Ajaxified' Formularfeldtyps

  1. Holen Sie alle Optionen (Schlüssel-Wert) über AJAX (zum Beispiel, indem Sie/countries.json) und Cache wenn möglich. (In diesem Fall ändern sich die Ländernamen nicht sehr oft.)
  2. Verwenden Sie selectize, select2 oder ein ähnliches Plugin, um die Optionen in das DOM einzufügen.
  3. Genießen Sie eine schnellere Formular :-)

Um Symfony von Abfragen alle Optionen zu verhindern (nicht notwendig: sie sind über AJAX geladen) Ich setMaxResults(0) zum QueryBuilder hinzugefügt, wenn die Form (durch Hinzufügen einer Option geladen wird über den Controller). Ja, das ist Kludi. Beim Absenden eines Formulars wird immer noch eine Abfrage durchgeführt, da überprüft werden muss, ob die ausgewählte Option vorhanden ist (und nach Einschränkungen sucht).

Ich möchte eine erstellen, die diese Funktionalität der aktuellen EntityType hinzufügt: laden Sie nicht die Optionen beim Rendern des Formulars, aber überprüfen Sie immer noch, ob die ausgewählte Option vorhanden ist. Ich habe manyexamples bezogen auf dynamically modifying a form gefunden, aber ich habe keine Beispiele gefunden, die sich auf das Ändern nur eines Formularfeldes beziehen, unabhängig von dessen Elternform.

Wie erstelle ich einen solchen Formularfeldtyp? Was ist ein guter Ausgangspunkt? Erweitern Sie EntityType, ChoiceType oder einen anderen Ansatz?

Ich benutze bereits Symfony 3.1, so dass lazy loading of form choices (Neu in Symfony 3.2) wird kein Problem sein. Ich bin mir nicht sicher, ob diese neue Funktion mit meinem Problem zusammenhängt.

+0

Mögliches Duplikat von [EntityType erweitern, um zusätzliche Optionen zuzulassen, die mit AJAX-Anrufen festgelegt werden] (http://stackoverflow.com/questions/30178424/extending-entitytype-to-allow-extra-choices-set-with-ajax-calls)) – Alsatian

Antwort

1

Ich schrieb ein Bündel (Alsatian/FormBundle), das tut, was Sie auf der Serverseite wollen.

  • How to avoid loading each entities by each form rendering:

    abstract class AbstractExtensibleChoicesType extends AbstractRoutableType 
    { 
        public function configureOptions(OptionsResolver $resolver) 
        { 
         $resolver->setDefault('choices',array()); 
        } 
    } 
    
  • Wie mit Cache-Inhalt das Formularfeld füllen:

, dass Ihre eigene Logik ist, würde ich vorschlagen: Erstellen Sie eine Steuerung, die nur zurückkehrt (als HTML):

<option value="1">Option 1</option> 
<option value="2">Option 2</option> 

In der Steuerung gesetzt maxage:

/* 
* @Route(...) 
* @Cache(maxage=64000) 
*/ 
public function getOptionsAction(Request $request) // Home 
{ 
    $choices = $this->getDoctrine()->getManager()->getRepository //.... 

    return $this->render(/*...*/); 
} 

verwendet Javascript diese URL zu laden und das HTML-Ergebnis in Ihrem Auswahlfeld zu setzen.

Wenn Sie etwas wie Select2 verwenden: Ihr Controller kann auch die Optionen als JSONReponse() zurückgeben, dann können Sie diesen JSON direkt von der Option select2 ajax laden (siehe Paketdokumentation, so verwende ich ihn).

Holen Sie sich die sumitted Auswahl in einem Formular :: PRE_SUBMIT Ereignis (auch PRE_SET_DATA, wenn Sie Ihr Formular bearbeiten), und diese Entscheidungen auf dem Gebiet einzuspritzen.

1

In Anbetracht Ihrer Anwendungsfall, wäre der beste Weg, eine Autocomplete zu verwenden. Hier ist ein Symfony bundle den ich benutzt habe und es ist genial. Ich habe einige sein Javascript (Autocompleter) überschreiben, um wenige Funktionalität gemäß meinem Fall zu verbessern.

+0

Danke für deinen Vorschlag, ich kann dieses Bündel als Inspiration verwenden. Ich möchte keine serverseitige Suchbehandlung, da die Suche auf der Clientseite viel schneller ist. Ich mag auch ihre Controller-Implementierung nicht, da Twig zum Rendern einer JSON-Ausgabe verwendet wird. Warum?! –

+0

Ja, anstatt den json mit Zweig zu rendern, schrieb ich in den Controller, um eine 'JsonResponse' des Ergebnisses zurückzugeben. Keine Notwendigkeit, einen Zweig für die json-Ausgabe zu rendern. – Jeet

+0

Ich bin mir nicht sicher, ob solch ein Bundle nützlich ist - füge einfach die ausgewählte Bibliothek zu deiner Seite + dem Init-Code hinzu, und hier tust du mit einem "normalen" Entitätstyp. In der Tat müssen Sie für den Leistungsgewinn zur Option "Ajax" gehen, um Ihre Einträge zu laden. – romaricdrigon

2

Autocomplete mit einer Ajax-Controller-Option sieht gut aus, aber Heres 'eine andere (vielleicht schneller?) -Option: Rendern Sie Ihr Formular durch Hinhaltet.

hinclude ist eine JS-Bibliothek verwendet, um die Last von Teilen einer Seite zu verschieben, dachte Ajax. Symfony wird mit integrierter Unterstützung geliefert (official documentation).

Wie yo es verwenden:

  • bewegen Sie die Form an einen anderen Controller-Aktion machen, nennen wir es formAction
  • hinclude.js auf Ihrer Seite (siehe offizielle Github)
  • Verwendung dieser Code enthalten um Ihr Formular zu rendern:

    {{render_hinclude (controller ('... :: form'), {'default': 'Wird geladen ...‚})}}

  • Sie wahrscheinlich in Ihrer ursprünglichen Controller-Aktion Handhabung halten Ihre Form wollen, so die "Aktion" der erzeugten Form wie folgt ändern:

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