AJAX & Snippets
In der Ära moderner Webanwendungen, in der die Funktionalität oft zwischen Server und Browser aufgeteilt ist, ist AJAX ein unverzichtbares Bindeglied. Welche Möglichkeiten bietet uns das Nette Framework in diesem Bereich?
- Senden von Teilen des Templates, sogenannten Snippets
- Übergabe von Variablen zwischen PHP und JavaScript
- Tools zum Debuggen von AJAX-Anfragen
AJAX-Anfrage
Eine AJAX-Anfrage unterscheidet sich im Grunde nicht von einer klassischen HTTP-Anfrage. Ein Presenter wird mit bestimmten Parametern aufgerufen. Und es liegt am Presenter, wie er auf die Anfrage reagiert – er kann Daten im JSON-Format zurückgeben, einen Teil des HTML-Codes senden, ein XML-Dokument usw.
Auf der Browserseite initialisieren wir die AJAX-Anfrage mit der Funktion fetch()
:
Auf der Serverseite erkennen wir eine AJAX-Anfrage mit der Methode $httpRequest->isAjax()
des die HTTP-Anfrage kapselnden Services. Zur Erkennung verwendet sie den HTTP-Header
X-Requested-With
, daher ist es wichtig, diesen mitzusenden. Innerhalb des Presenters kann die Methode
$this->isAjax()
verwendet werden.
Wenn Sie Daten im JSON-Format senden möchten, verwenden Sie die Methode sendJson()
. Die Methode beendet auch die Aktivität des
Presenters.
Wenn Sie planen, mit einem speziellen Template für AJAX zu antworten, können Sie dies wie folgt tun:
Snippets
Das stärkste Mittel, das Nette zur Verbindung von Server und Client bietet, sind Snippets. Dank ihnen können Sie eine gewöhnliche Anwendung mit minimalem Aufwand und wenigen Codezeilen in eine AJAX-Anwendung verwandeln. Wie das Ganze funktioniert, demonstriert das Beispiel Fifteen, dessen Code Sie auf GitHub finden.
Snippets, oder Ausschnitte, ermöglichen es, nur Teile der Seite zu aktualisieren, anstatt die gesamte Seite neu zu laden. Dies ist nicht nur schneller und effizienter, sondern bietet auch eine komfortablere Benutzererfahrung. Snippets erinnern vielleicht an Hotwire für Ruby on Rails oder Symfony UX Turbo. Interessanterweise hat Nette Snippets bereits 14 Jahre früher eingeführt.
Wie funktionieren Snippets? Beim ersten Laden der Seite (nicht-AJAX-Anfrage) wird die gesamte Seite einschließlich aller Snippets geladen. Wenn der Benutzer mit der Seite interagiert (z. B. auf einen Button klickt, ein Formular absendet usw.), wird anstelle des Ladens der gesamten Seite eine AJAX-Anfrage ausgelöst. Der Code im Presenter führt die Aktion aus und entscheidet, welche Snippets aktualisiert werden müssen. Nette rendert diese Snippets und sendet sie in Form eines Arrays im JSON-Format. Der Verarbeitungscode im Browser fügt die empfangenen Snippets wieder in die Seite ein. Es wird also nur der Code der geänderten Snippets übertragen, was Bandbreite spart und das Laden im Vergleich zur Übertragung des gesamten Seiteninhalts beschleunigt.
Naja
Zur Verarbeitung von Snippets auf der Browserseite dient die Bibliothek Naja. Diese installieren Sie als node.js-Paket (zur Verwendung mit Anwendungen wie Webpack, Rollup, Vite, Parcel und anderen):
…oder fügen Sie sie direkt in das Seiten-Template ein:
Zuerst muss die Bibliothek initialisiert werden:
Um aus einem gewöhnlichen Link (Signal) oder dem Absenden eines Formulars eine AJAX-Anfrage zu machen, genügt es, den
entsprechenden Link, das Formular oder den Button mit der Klasse ajax
zu kennzeichnen:
Neuzeichnen von Snippets
Jedes Objekt der Klasse Control (einschließlich des Presenters selbst) verfolgt, ob Änderungen
aufgetreten sind, die sein Neuzeichnen erfordern. Dazu dient die Methode redrawControl()
:
Nette ermöglicht eine noch feinere Kontrolle darüber, was neu gezeichnet werden soll. Die genannte Methode kann nämlich als Argument den Namen des Snippets entgegennehmen. Man kann also auf der Ebene von Template-Teilen invalidieren (sprich: Neuzeichnen erzwingen). Wenn die gesamte Komponente invalidiert wird, wird auch jedes ihrer Snippets neu gezeichnet:
Snippets in Latte
Die Verwendung von Snippets in Latte ist extrem einfach. Um einen Teil des Templates als Snippet zu definieren, umschließen
Sie ihn einfach mit den Tags {snippet}
und {/snippet}
:
Das Snippet erstellt in der HTML-Seite ein <div>
-Element mit einer speziellen generierten id
.
Beim Neuzeichnen des Snippets wird dann der Inhalt dieses Elements aktualisiert. Daher ist es notwendig, dass beim erstmaligen
Rendern der Seite auch alle Snippets gerendert werden, auch wenn sie anfangs leer sein mögen.
Sie können auch ein Snippet mit einem anderen Element als <div>
erstellen, indem Sie ein n:Attribut
verwenden:
Snippet-Bereiche
Snippet-Namen können auch Ausdrücke sein:
So entstehen mehrere Snippets item-0
, item-1
usw. Wenn wir ein dynamisches Snippet direkt
invalidieren würden (zum Beispiel item-1
), würde nichts neu gezeichnet werden. Der Grund dafür ist, dass Snippets
wirklich wie Ausschnitte funktionieren und nur sie selbst direkt gerendert werden. Im Template gibt es jedoch faktisch kein
Snippet namens item-1
. Dieses entsteht erst durch die Ausführung des Codes um das Snippet herum, also der
foreach-Schleife. Wir kennzeichnen daher den Teil des Templates, der ausgeführt werden soll, mit dem Tag
{snippetArea}
:
Und lassen sowohl das Snippet selbst als auch den gesamten übergeordneten Bereich neu zeichnen:
Gleichzeitig ist es ratsam sicherzustellen, dass das Array $items
nur die Elemente enthält, die neu gezeichnet
werden sollen.
Wenn wir mittels des {include}
-Tags ein anderes Template einfügen, das Snippets enthält, muss das Einfügen des
Templates ebenfalls in eine snippetArea
eingeschlossen und diese zusammen mit dem Snippet invalidiert werden:
Snippets in Komponenten
Sie können Snippets auch in Komponenten erstellen und Nette wird sie automatisch neu zeichnen. Es
gibt jedoch eine gewisse Einschränkung: Für das Neuzeichnen von Snippets ruft Nette die Methode render()
ohne
Parameter auf. Das bedeutet, dass die Übergabe von Parametern im Template nicht funktioniert:
Senden von Benutzerdaten
Zusammen mit den Snippets können Sie beliebige zusätzliche Daten an den Client senden. Schreiben Sie diese einfach in das
payload
-Objekt:
Parameterübergabe
Wenn wir einer Komponente über eine AJAX-Anfrage Parameter senden, seien es Signalparameter oder persistente Parameter,
müssen wir bei der Anfrage deren globalen Namen angeben, der auch den Namen der Komponente enthält. Den vollständigen Namen des
Parameters gibt die Methode getParameterId()
zurück.
Und die handle-Methode mit den entsprechenden Parametern in der Komponente: