Symfony

Wie erhält man den Wert eines Symfony-Formular-Felds in JQuery?

In dem Beitrag JQuery: Wie erhält man den Wert eines Formularfelds? habe ich bereits beschrieben, wie man mithilfe von JQuery den Wert eines Formularfelds aus einem normalen HTML-Formular auslesen kann.

Bei einem Symfony-Formular ist das jedoch auf den ersten Blick nicht so einfach. Jedoch stellt uns Symfony Hilfsfunktionen bereit um auf HTML-Attribute von Formularelementen zugreifen zu können: Die vars-Eigenschaft der symfonischen Formularelemente. Hier ein Beispiel in Twig-Syntax, das den Inhalt des HTML-Attributs name des Formulars form ausgibt:

{{ form.vars.name }} 

Zum Test erzeugen wir eine Formularklasse mit zwei Feldern:

  • Titel (title)
  • Beschreibung (description)

Die dazugehörige Formular-Klasse sieht zum Beispiel so aus:

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class ActivityType extends AbstractType {

    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder
                
                ->add('title', TextType::class)
                ->add('description', TextareaType::class)
        ;
    }

}

Der dazugehörige Controller sieht z. B. so aus:

<?php

namespace App\Controller;

use App\Form\ActivityType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

/**
 * @Route("/activity")
 */
class ActivityController extends AbstractController
{
    /**
     * @Route("/new", name="activity_new", methods={"GET","POST"})
     */
    public function new(Request $request): Response
    {
        $form = $this->createForm(ActivityType::class);
        $form->handleRequest($request);

        return $this->render('activity/new.html.twig', [
            'form' => $form->createView(),
        ]);
    }

}

Nun soll per JavaScript bzw. jQuery der Wert des Felds “title” ausgelesen werden. Dies mag zum Beispiel der Fall sein, wenn die Daten per AJAX-Call im Hintergrund irgendwo hingeschickt werden sollen.

Aber woher wissen wir, welche ID das Formularfeld hat? Die ID des Formularfelds ist nirgends direkt ersichtlich. Wir könnten zwar die ID des Felds ermitteln indem wir die Seite im Browser anzeigen lassen und die ID per Blick in den Quelltext auslesen – aber das ist langwierig und kein flüssiger Entwicklungsprozess.

Symfony stellt uns Funktionen zur Verfügung um die ID eines Formulars und dessen Felder auszulesen: formVariable.vars.id bzw. formVariable.formField.vars.id Dabei müssen wir formVariable durch den Variablennamen des Formulars ersetzen – und formField müssen wir durch den Feldnamen ersetzen. Sehen wir uns das in einem Beispiel an:

{% form(form) %}

<script>
    let title = $("#{{ form.title.id }}").val();
</script>

Für einen vollständigen Test hier noch ein Beispiel. Dieses Beispiel zeigt das Formular mit zwei Eingabefeldern. Beim Klick auf den Button, wird das Feld “title” ausgelesen und sein Inhalt wird in einem Dialogfeld ausgegeben. Mit “event.preventDefault();” wird verhindert, dass das Formular tatsächlich abgesendet wird. So kann man beliebig oft hintereinander testen.

<!DOCTYPE html>
<html>
    <head>
        <script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>
        <!-- Bootstrap wird nur eingebunden, damit unser Formular etwas hübscher aussieht :-) -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
    </head>
    <body class="container">
        <h1>Test: Wie erhält man den Wert eines Symfony-Formular-Felds in JQuery</h1>
        {{ form_start(form) }}
            {{ form_widget(form) }}
            <button type="submit" class="btn">{{ button_label|default('Save') }}</button>
        {{ form_end(form) }}
    </body>
    <script>
        $('#{{ form.vars.id }}').closest('form').on('submit', function (event) {
            let title = $('#{{form.title.vars.id}}').val();
            alert(title);
            event.preventDefault();
        });    
    </script>
</html>

Wenn wir die Seite im Browser aufrufen, erhalten wir folgende HTML-Ausgabe:

<!DOCTYPE html>
<html>
    <head>
        <script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>
        <!-- Bootstrap wird nur eingebunden, damit unser Formular etwas hübscher aussieht :-) -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css">
    </head>
    <body>
        <h1>Test: Wie erhält man den Wert eines Symfony-Formular-Felds in JQuery</h1>
        <form name="activity" method="post">
            <div id="activity">
                <div class="form-group">
                    <label for="activity_title" class="required">Title</label>
                    <input type="text" id="activity_title" name="activity[title]" required="required" maxlength="255" class="form-control" />
                </div>
                <div class="form-group">
                    <label for="activity_description">Description</label>
                    <textarea id="activity_description" name="activity[description]" class="form-control"><textarea>
                </div>
                <input type="hidden" id="activity__token" name="activity[_token]" value="SQDbpMGlbR4mi_T_hIdZiHP-HhlXKYDsYhV9b-jgrP4" />
            </div>
            <button type="submit" class="btn">Save</button>
        </form>
    </body>
    <script>
        $('#activity').closest('form').on('submit', function (event) {
            let title = $('#activity_title').val();
            alert(title);
            event.preventDefault();
        });    
    </script>
</html>

Die Ausgabe im Browser sollte ungefähr so aussehen:

Ausgabe unseres Test-Formulars im Browser

Wichtig ist hier, dass das form-Element in unserem HTML-Code keine ID erhält. Wenn wir also in Javascript den Selector #activity verwenden bzw. $('#{{ form.vars.id }}') erhalten wir nicht das Formular, sondern das darin enthaltene div-Element!

Um per jQuery unser Formular-Element zu erhalten, holen wir uns anhand der Formular-ID das div-Element und anschließend mit .closest('form') das umgebende Formular.

Dieses Vorgehen hat einen Nachteil: Es hängt vom verwendeten Form-Theme ab, ob innerhalb des Forms ein div-Element mit der ID des Formulars gerendert wird.

Eine bessere Möglichkeit ist, dass Formular anhand seines Namens zu identifizieren. Die Schreibweise im Template ist für diese stabilere Variante etwas komplizierter:

// Gut lesbare Variante
$('#{{ form.vars.id }}').closest('form');

// Stabile Variante
$('form[name={{ form.vars.name }}]');

Die Formularfelder enthalten jeweils das Attribut id und können daher direkt darüber selektiert werden: Z. B. mit $('#activity_title') bzw. mit $('#{{ form.title.vars.id }}')

Weiterführende Links

https://stackoverflow.com/questions/11654449/jquery-get-form-field-value
https://api.jquery.com/val
https://www.w3schools.com/jquery/html_val.asp
https://symfony.com/doc/current/forms.html


René Pöpperl

Seit 2010 arbeite ich als Softwareentwickler. Mein hauptsächlichen Interessen liegen in gut durchdachtem UI-Design und hoher Code-Qualität.

Consent Management Platform von Real Cookie Banner