Einleitung
Wenn ihr in TYPO3 schon mal eine Summary Page im Formular ergänzt habt, kennt ihr das Standard-Styling dieser Seite: alle Formulardaten werden einfach nacheinander aufgelistet – Labels links, Feldwerte rechts (bei Verwendung von Bootstrap).
Bei umfangreichen Formularen wird diese simple Auflistung definitiv zu unübersichtlich. Nicht nur, weil sich Labels wiederholen können – etwa für die beiden Felder "Stadt" einer Rechnungs- und Lieferadresse.
Daher widmen wir uns hier der individuellen Ausgabe auf der Übersichtsseite.
Ausgangslage
Dieses Tutorial ist die Fortsetzung des Beitrags über Multi-Step-Formulare. Im ersten Teil habe ich ich eine Stepper-Navigation in einem mehrseitigen Formular ergänzt.
Unser Beispielformular besteht aus vier Seiten:
- Produktauswahl
- Rechnungsadresse
- Lieferadresse (optional)
- Übersicht
Der Formularschritt mit der Lieferadresse kann vom Nutzer übersprungen werden, wenn er auf der vorherigen Seite die Checkbox "Rechnungsadresse entspricht der Lieferadresse." aktiviert.
Die Code-Snippets auf dieser Seite zeigen nur die jeweils wichtigsten Bestandteile. Den vollständigen Code findet ihr in der Demo-Extension auf GitHub.
Ausgabe aller Felder, gruppiert nach Formularseiten
Standardmäßig nutzt die Summary Page den ViewHelper formvh:renderAllFormValues, um alle Formular-Elemente in einer Schleife zu durchlaufen. Innerhalb davon werden dann die einzelnen Elemente bzw. Felder auszugeben. Als Wert wird dem ViewHelper dafür {page.rootForm} übergeben.
Mit nur wenigen Anpassungen können wir die Felder nach Formularseiten gruppieren und den Titel der jeweiligen Seite als Überschrift ergänzen:
<f:for each="{page.rootForm.pages}" as="step">
<f:if condition="{step.type} != 'SummaryPage'">
<h2>{formvh:translateElementProperty(element: step, property: 'label')}</h2>
</f:if>
<formvh:renderAllFormValues renderable="{page.rootForm.pages.{step.index}}" as="formValue">
<!-- Rendering der Felder (identisch zum Original-Template) -->
</formvh:renderAllFormValues>
</f:for>
Das führt im Ergebnis schon zu etwas mehr Struktur. Um die Übersicht aber wirklich nutzerfreundlich zu gestalten, ist mehr Aufwand erforderlich.
Optimierte Ausgabe einzelner Feldwerte
Die beiden Addressblöcke werden deutlich lesbarer, wenn man die Feld-Labels weglässt und die eingegebenen Daten menschenlesbar ausgibt:
Michael Mustermann Beispielweg 1 54321 Musterstadt Deutschland
Hierfür wäre es praktisch, einzelne Formularwerte auslesen zu können. Der zweite ViewHelper formvh:renderFormValue, der ab TYPO3 v10 verfügbar ist, erlaubt genau das. Ihr übergebt ihm dafür das gewünschte Formular-Element mit dem Identifier aus der Formular-Definition.
Für die Rechnungsadresse kann das z.B. so aussehen:
<p>
<formvh:renderFormValue renderable="{page.rootForm.elements.firstName--billing}" as="formValue">
{formValue.processedValue}
</formvh:renderFormValue>
<formvh:renderFormValue renderable="{page.rootForm.elements.lastName--billing}" as="formValue">
{formValue.processedValue}<br>
</formvh:renderFormValue>
<formvh:renderFormValue renderable="{page.rootForm.elements.address--billing}" as="formValue">
{formValue.processedValue}<br>
</formvh:renderFormValue>
<formvh:renderFormValue renderable="{page.rootForm.elements.postalCode--billing}" as="formValue">
{formValue.processedValue}
</formvh:renderFormValue>
<formvh:renderFormValue renderable="{page.rootForm.elements.city--billing}" as="formValue">
{formValue.processedValue}<br>
</formvh:renderFormValue>
<formvh:renderFormValue renderable="{page.rootForm.elements.country--billing}" as="formValue">
{formValue.processedValue}
</formvh:renderFormValue>
</p>
Ergänzung von Conditions
In unserem Beispielformular kann der Nutzer eine Checkbox aktivieren, um die Lieferadresse zu überspringen. Dies können wir auf der Übersichtsseite berücksichtigen:
<formvh:renderFormValue renderable="{page.rootForm.elements.address-is-identical}" as="formValue">
<f:if condition="{formValue.value}">
<f:then>
<p>{formvh:translateElementProperty(element: formValue.element, property: 'label')}</p>
</f:then>
<f:else>
<p>
<formvh:renderFormValue renderable="{page.rootForm.elements.firstName--shipping}" as="formValue">
{formValue.processedValue}
</formvh:renderFormValue>
<!-- Rendering der weiteren Felder der Versandadresse (siehe Demo) -->
</p>
</f:else>
</f:if>
</formvh:renderFormValue>
Falls die Checkbox aktiv ist, wird deren Label "Rechnungsadresse entspricht der Lieferadresse." ausgegeben. Andernfalls rendert man die Felddaten der Rechnungsadresse.
Schleifen für Teilbereiche eines Formulars, z.B. Fieldsets
Wie ihr seht, kann das Rendering einzelner Felder sehr aufwändig werden. Aber wir müssen nicht alle Felder auf diese Weise ausgeben.
Nachfolgend iterieren wir durch alle Formularfelder, die im Fieldset "Produkte" angelegt sind:
<formvh:renderAllFormValues renderable="{page.rootForm.elements.fieldsetProducts}" as="formValue">
<!-- Rendering der Produktfelder (siehe Demo) -->
</formvh:renderAllFormValues>
Auf diese Weise könnte man eine Reihe von Bestellformularen anlegen, bei denen sich lediglich die Produkte unterscheiden. Das einmalig individualisierte SummaryPage-Template kann dann für all diese Formulare verwendet werden.
Buttons zur Änderung eingegebener Daten in einem Formularschritt
Auf der Übersichtsseite haben wir die eingegebenen Formulardaten inzwischen sinnvoll strukturiert.
Durch die Einrichtung der Stepper-Navigation im ersten Teil wissen wir bereits, wie man zu einem bestimmten Formularschritt zurückspringen kann.
Daher ist es nun ein Leichtes, für jeden Block auf der Übersichtsseite einen "Bearbeiten"-Button zu ergänzen, der den entsprechenden Formularschritt öffnet.
Der Button wird im SummaryPage-Template jeweils am gewünschten Textblock ergänzt. Den Indexwert des Formularschritts setzen wir in diesem Fall manuell. Falls ihr in eurem Formular – wie oben gezeigt – durch die einzelnen Seiten iteriert, könnt ihr in deren jeweiligen Indexwert mit value="{page.index}" auslesen und anwenden.
<f:form.button property="__currentPage" value="2"
class="btn btn-primary btn-sm"
additionalAttributes="{respectSubmittedDataValue: false}"
formnovalidate="formnovalidate">
{f:translate(key: 'LLL:EXT:form_multistep/Resources/Private/Language/form.xlf:btn.edit.label')}
</f:form.button>
Wir benötigen hier übrigens keine Abfrage, ob die Formularseite mit Indexwert 2 aktiv ist! Wenn im Beispielformular die Seite mit der Lieferadresse übersprungen wird – die Seite also inaktiv ist –, öffnet ein Klick auf den Button zu dieser Seite stattdessen die vorherige, aktive Seite.
Falls euer Formular komplexer ist, ließe sich der Button-Wert aber natürlich mit einer passenden Condition setzen.
Demo
Die TYPO3-Extension "form_multistep" liefert ein komplettes Demo-Setup mit. Neben dem Formular und den notwendigen Templates habe ich diesmal auch eine grundlegende TypoScript-Konfiguration mit PAGE-Objekt ergänzt. Ihr könnt das TypoScript der Extension einfach in einem neuen Seitenbaum einbinden und erhaltet direkt ein (einigermaßen) ansprechendes Design mit Bootstrap sowie eigenen Styles für die Stepper-Navigation.
Die Formular-Konfiguration wird bei Installation der Extension automatisch in TYPO3 registriert. Da alle Konfigurationen über einen neuen Formular-Prototyp gesetzt sind, beeinflusst das nicht eure ggf. bestehenden Formulare.
Getestet wurde die Extension mit TYPO3 v11 und v12.