4. Einen Webserver programmieren
4.6 HTML und Server-Code trennen mit ejs-Templates
Wenn Sie die Übungsaufgaben aus dem letzten Abschnitt gelöst haben,
dann werden Sie wohl häufig HTML-Quelltext als String innerhalb
der .js
-Datei haben, die den Server-Quelltext enthält.
Hier ist ein Beispiel aus meinem Code:
var response = htmlHeader +
`<body><p>File ` + filename + ` successfully uploaded.</p>
<p><a href="index.html">back</html></p></body></html>` ;
return res.send(response);
Vielleicht haben Sie auch den Nachteil gespürt: jedes Mal, wenn die das Format Ihrer Seiten ändern wollen, müssen Sie den Server-Quelltext ändern und somit auch den Server neu starten. Das wäre bei echten Anwendungen natürlich ein No-Go. Besser wäre es doch, den HTML-Code in eine Datei auszulagern, die dann bei Bedarf vom Server gelesen wird. Betrachten Sie nochmal obiges Beispiel, jetzt mit Farbmarkierung:
var response = htmlHeader +
`<body><p>File ` + filename + ` successfully uploaded.</p>
<p><a href="index.html">back</html></p></body></html>` ;
return res.send(response);
Da sehen Sie auch das Problem mit dem Auslagern in eine externe HTML-Datei: die Variable
filename
soll dynamisch in den HTML-Text eingesetzt werden. Wir bräuchten
also nicht nur eine normale externe HTML-Datei, sondern eine
HTML-Datei mit Platzhaltern.
Diese Platzhalter müssen irgendwie als solche markiert sein.
bla.html
und ersetze Platzhalter
mit Werten
Erste Schritte mit ejs-Templates: alles offline
Speichern Sie 01-templates-strings.js. Hier ist der Quelltext:const ejs = require('ejs');
const template = "Guten Tag, <%=anrede%> <%=name%>.";
let string1 = ejs.render(template, {anrede: "sehr geehrte Frau Professor", name: "Buchbinder"});
let string2 = ejs.render(template, {anrede: "lieber", name: "Alois"});
console.log(string1);
console.log(string2);
Starten Sie das Programm 01-templates-strings.js nun auf der Konsole:
node 01-templates-strings.js
Guten Tag, sehr geehrte Frau Professor Buchbinder.
Guten Tag, lieber Alois.
In dem String "Guten Tag, <%=anrede%> <%=name%>."
markieren
die Symbole <%
und %>
, dass hier ein Platzhalter
drinsteht. Die Funktion ejs.render
ersetzt dann den Platzhalter
durch die übergebenen Werte. In unserem Beispiel gibt es zwei Platzhalter,
anrede
und name
; in Zeile 5 zum Beispiel wird dann dürch Übergeben des
Dictionarys {anrede: "lieber", name: "Alois"}
der Platzhalter andere
durch
den String "lieber"
erstzt.
Das Platzhalter-durch-Werte-Ersetzen in ejs ist aber noch komplexer und flexibler: Sie können
zwischen den <%
...%>
im Prinzip beliebigen
Javascript-Code schreiben; mit <%=
machen Sie deutlich, dass hier der Wert
des Platzhalters als String eingefügt werden soll. Wenn das <%
nicht von einem
=
gefolgt ist, können Sie Javscript-Code hinschreiben, wie zum Beispiel
const ejs = require('ejs');
const fs = require('fs');
language = 'English'
months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
let templateString = `Die Namen der Monate auf <%=language%> sind
<% for (i in listOfMonthNames) {%><%=listOfMonthNames[i]%>,
<% } %>`;
const result = ejs.render(templateString, {language : 'English', listOfMonthNames : months});
console.log(result);
Sie können es noch komplexer machen, z.B. ein if
einfügen und den rot markierten
String oben ersetzen durch
`Die Namen der Monate auf <%=language%> sind
<% for (i in listOfMonthNames) {%><%=listOfMonthNames[i]%><% if (i < listOfMonthNames.length-1) {%>, <%} else {%>.<%}%><% } %>`
Schreiben Sie ein node-Programm (alles offline, kein Web hier), das zwei
Dateien einliest, sagen wir textfile.txt
und
template.ejs
und den Inhalt von textfile.txt
Zeile für Zeile und pro Zeile Wort für Wort in einen HTML-Table übersetzt.
Hier ist ein Beispiel:
textfile.txt
:
Hello. This is a list of lines. Each line contains a couple of words.
<table> <tr><td>Hello.</td><td>This</td><td>is</td><td></td> </tr> <tr><td>a</td><td>list</td><td>of</td> </tr> <tr><td>lines.</td><td>Each</td><td>line</td> </tr> <tr><td>contains</td><td>a</td><td>couple</td> </tr> <tr><td>of</td><td>words.</td> </tr> </table>
Ihr Programm solll also also die Datei als String einlesen, diesen dann erstmal
in separate Zeilen zerlegen, und dann jede Zeile in separate, durch Whitespace
separierte Wörter zerlegen.
Das Ergebnis könnte dann zum Beispiel ein Array aus Arrays sein, dass Sie
der Funktion
render
übergeben; Ihre Datei template.ejs
beinhaltet
höchstwahrscheinlich zwei
verschachtelte for
-Schleifen.
Jetzt könnten Sie im Prinzip Ihre Html-Dateien mit Templates schreiben, sie dann mit
fileReadSync
oder ähnlichem in Ihrem Server-Quellcode einlesen und per
ejs.render
die Platzhalter durch Werte ersetzen, um dynamisch Inhalt in
Html zu übersetzen.
Natürlich geht das noch einfacher:
wenn res
Ihr Http-Response-Objekt ist, können Sie einfach per
res.render("filename.ejs", {var1 : value1, var2 : value2 ...}
den in
filename.ejs
enthaltenen Html-Text mit Platzhaltern rendern, analog zu ejs.render
. Das
Lesen aus der Datei, Platzhalter
durch Werte ersetzen und Ergebnis in den Response schreiben und zurückschicken erledigt
alles die Funktion
res.render
.
Als Beispielcode nehmen Sie gerne
Übungsaufgabe Schreiben Sie eine Anwendung mit Server, der den Nutzer durch ein "Anmeldeformular" führt. Das Formular soll mehrere Seiten haben, beispielsweise die folgenden:
- Account erstellen, Nutzername und Passwort festlegen.
- Login mit Nutzernamen und Passort.
- Nach erfolgtem Login: mehrere Seiten mit Eingabefelder für jeweils Name, Geburtsdatum, Adresse, Telefonnummer, Email-Adresse.
Jede Seite soll einen Link auf die nächste und die vorherige Seite haben. Die ganze Anwendung soll persistentes Verhalten zeigen. Wenn Sie also innerhalb der verschiedenen Seiten navigieren, sollen bereits eingetragene Daten nicht verloren