Übungen¶
Übung 0¶
Infrastruktur einrichten
- wählen Sie eine IDE aus und installieren Sie diese
- richten Sie sich ein Git-Repository ein (z.B.
WebTech26) - erstellen Sie im Ordner
WebTech26eineindex.htmlund versuchen Sie darin bereits einige Inhalte einzupflegen, z.B. eine kleine persönliche Webseite oder eine Startseite von der aus alle Übungen erreichbar sind o.ä. - commiten und pushen Sie Ihr Repository auf einen zentralen Dienst (siehe)
- laden Sie mich zu Ihrem Git-Dienst ein (siehe)
Übung 1¶
Übungsaufgabe 1 (HTML)
- Erstellen Sie in einem
Uebung1-Ordner eine Dateiindex.html. Dasbody-Element soll einheader-Element, einmain-Element und einfooter-Element enthalten. -
Erstellen Sie im
Uebung1-ordner zwei Unterordner:bilderundunterseiten.- In dem Ordner
unterseitenerstellen Sie eine Dateiplan.html. Dasbody-Element darin soll ebenfalls einheader-Element, einmain-Element und einfooter-Element enthalten. - In den Ordner
bilderlegen Sie campus_wh.jpg und fiw.jpg ab.
- In dem Ordner
-
die
index.htmlsollte ungefähr so gestaltet werden:
-
die
plan.htmlsollte ungefähr so gestaltet werden:
Für die Tabelle können Sie folgende Einträge verwenden:
<tr> <td>B21</td> <td>Programmierung 2</td> <td>5</td> </tr> <tr> <td>B22</td> <td>Mathematik 2</td> <td>6</td> </tr> <tr> <td>B23</td> <td>Software-Engineering 1</td> <td>5</td> </tr> <tr> <td>B24</td> <td>Webtechnologien</td> <td>5</td> </tr> <tr> <td>B25</td> <td>BWL 2: Rechnungswesen</td> <td>5</td> </tr> <tr> <td>B26</td> <td>1. Fremdsprache 2</td> <td>4</td> </tr> -
Sie können selbstverständlich beliebig kreativ werden und die Seite nach eigenen Bedürfnissen erweitern.
-
Committen und pushen Sie Ihre Lösung in Ihr Remote-Repo!
Übung 2¶
Übungsaufgabe 2 (CSS)
- Erstellen Sie (falls noch nicht geschehen) eine
index.html-Datei in Ihrem Repository-Ordner (also z.B.WebTech26) derart, dass diese direkte Links auf Ihre Lösungen der Übungen enthalten (z.B. in einer Tabelle oder einer Liste). - Kopieren Sie den Ordner
Uebung1in den OrdnerUebung2(also inkl. Ordnerbilderundunterseiten). - Legen Sie sich im
Uebung2-Ordner einen Ordnerstylesan. Erstellen Sie in demstyles-Ordner eine Dateimystyles.css. - Fügen Sie im
<head>-Bereich derindex.htmleine logische Verknüpfung zurmystyles.css-Datei ein (<link href="./styles/mystyles.css" rel="stylesheet">). - In
mystyles.cssdefinieren Sie (versuchen Sie so viel wie möglich der folgenden Punkte umzusetzen, probieren Sie auch ruhig selbst etwas aus):- Verdana als Schriftart für das ganze Dokument
- der
<header>soll im HTW-Grau als Hintergrundfarbe (siehe HTW Corporate Design). - das Icon soll links und der Text rechts im Header sein (siehe Flexbox)
- die Überschrift soll im HTW-Blau sein
- die zweite Überschrift soll etwas eingerückt sein (wie die Liste - siehe margin)
- die einzelnen List-Items sollen einen Rahmen haben (siehe border)
- die einzelnen Hyperlinks in der Liste sollen schwarz sein und keine Text-Dekoration mehr aufweisen (nicht unterstrichen - siehe Styling a)
- die Links zum Semesterplan und zur Mensa sollen rechts als Icons erscheinen. Die Icons sind hier: plan.png und essen.png
- der
<footer>soll in HTW-Orange sein, der Text zentriert und ganz unten in der Seite (siehe sticky footer) - ungefähr so:
- wenn Sie über die Liste hovern, soll die Schrift, im HTW-Grün und Rahmen und Hintergrundfarbe geändert werden, ungefähr so:
- in
plan.htmlsollen die Tabelle gestaltet werden und der Link als Button, ungefähr so:
- wenn Sie über die Tabelle hovern, soll sich die Hintergrundfarbe der Tabellenzeile ändern (und villeicht auch noch
box-shadow, ungefähr so:
-
Sie können auch alles ganz anders machen, Hauptsache, Sie probieren ein paar Selektoren aus und ein paar Eigenschaften!
-
Committen und pushen Sie Ihre Lösung in Ihr Remote-Repo!
Übung 3¶
Übungsaufgabe 3 (Grid und Einheiten)
- Erstellen Sie einen
Uebung3-Ordner und darin eine Dateiuebung3.html. Kopieren Sie diesen Inhalt inuebung3.html(Rechtsklick auf die Seite undSeitenquelltext anzeigen- falls ein<script>-Element unten ist, können Sie es löschen; Sie können es auch unten kopieren). - Laden Sie sich hier die Datei images.zip herunter, entpacken Sie sie und schieben Sie den
images-Ordner samt Inhalt in denUebung3-Ordner. - Implementieren Sie die
uebung3.htmlso, dass ungefähr folgendes Aussehen entsteht:
- Sie können die CSS-Eigenschaften innerhalb der
uebung3.htmlim<style>-Element definieren oder wieder in einer externen Datei. - Ziele der Übung sind die Anwendung von CSS-Grid (siehe z.B. hier) sowie die Verwendung von Größen und Einheiten (siehe z.B. hier). Lassen Sie Ihrer Kreativität freien Lauf!
Vorlage uebung3.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Uebung 3</title>
</head>
<body>
<header>
<h2>STÄDTE</h2>
</header>
<main>
<section class="wrapper">
<div class="citycard">
<div class="cityimage">
<img src="./images/berlin.png" alt="Berlin">
</div>
<div class="cityname">
<p>Berlin</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/bernau.png" alt="Bernau">
</div>
<div class="cityname">
<p>Bernau</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/brandenburg.png" alt="Brandenburg">
</div>
<div class="cityname">
<p>Brandenburg</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/bremen.png" alt="Bremen">
</div>
<div class="cityname">
<p>Bremen</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/bremerhaven.png" alt="Bremerhaven">
</div>
<div class="cityname">
<p>Bremerhaven</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/madrid.png" alt="Madrid">
</div>
<div class="cityname">
<p>Madrid</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/magdeburg.png" alt="Magdeburg">
</div>
<div class="cityname">
<p>Magdeburg</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/mainz.png" alt="Mainz">
</div>
<div class="cityname">
<p>Mainz</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/mannheim.png" alt="Mannheim">
</div>
<div class="cityname">
<p>Mannheim</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/Marburg.png" alt="Marburg">
</div>
<div class="cityname">
<p>Marburg</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/newyork.png" alt="New York">
</div>
<div class="cityname">
<p>New York</p>
</div>
</div>
<div class="citycard">
<div class="cityimage">
<img src="./images/stockholm.png" alt="Stockholm">
</div>
<div class="cityname">
<p>Stockholm</p>
</div>
</div>
</section>
</main>
<footer>
</footer>
</body>
</html>
Übung 4¶
Übungsaufgabe 4 (Bootstrap)
- Erstellen Sie einen
Uebung4-Ordner und darin eine Dateiuebung4.html. - Implementieren Sie die
uebung4.htmlmithilfe von Bootstrap so, dass ungefähr folgendes Aussehen entsteht:
- Ziel der Übung ist die Anwendung von CSS-Bootstrap und das Erstellen von Formularen.
Übung 4a¶
Übungsaufgabe 4a (JavaScript)
- Erweitern Sie einen die Datei
uebung4.htmlaus demUebung4-Ordner. - Sind in das Formular Daten eingegeben und wird der
Registrieren-Button gedrückt, dann erscheint mithilfe einer JavaScript-Funktion:
- Wird der
Abbrechen-Button gedrückt, werden alle bereits eingegebenen Daten wieder aus den Textfeldern entfernt. - Prüfen Sie außerdem die Eingaben (siehe Validation):
- Achtung! Sollten Ihre Eingabefelder in ein
<form> ... </form>-Element eingebettet sein und sollte dann noch IhrRegistrieren-Button vmtype="submit"sein, dann sollte als erste Anweisung in Ihrer Funktionevent.preventDefault()stehen, um die Behandlung dessubmit-Ereignisses zu unterdrücken. (Die Anweisung schadet in keinem Fall - können Sie also sicherheitshalber hinzufügen).
Übung 5¶
Übungsaufgabe 5 (JavaScript, DOM)
- Laden Sie aus Moodle die Datei
uebung5.zipherunter, entpacken Sie sie und schieben den Ordneruebung5in Ihren Projektordner. - In der Datei
uebung5.htmlsind einige Dinge vorbereitet:- eine Tabelle mit leerem
<tbody>. Der<tbody>hat dieid='tbody', - wird die Seite geladen, wird die
init()-Funktion aufgerufen (onload='init()'), - eine JavaScript-Funktion
getStaedte(). Diese Funktion "holt" die Dateistaedte.json(liegt imUebung5-Ordner) und gibt sie zurück, - eine Variable
staedtearr, in der das Array geladen werden soll, das diestaedte.jsonenthält. Achtung! das Array selbst ist der Wert, der im JSON unter dem Schlüsselstaedtesteht (schauen Sie sich die Dateistaedte.jsonan), - eine JavaScript-Funktion
createTable(), die Sie verwenden sollen, um die Tabelle mit Werten zu befüllen. Schauen Sie sich auch die Kommentare inuebung5.htmlan.
- eine Tabelle mit leerem
- Befüllen Sie die Tabelle unter Verwendung der Daten aus
staedte.json- für jede neu entstehende Tabellenzeile müssen Sie fünf neue
td-Objekte kreieren und diese an ein neu kreiertestr-Objekt anhängen. Dastr-Obejkt hängen Sie wiederum an dentbody. - die Nummer in der ersten Spalte erstellen Sie einfach fortlaufend mit dem Wert von
nr, den Sie für jede Zeile erhöhen. - der
Info-Button ist ein Hyperlink mit der Bootstrap-Klassebtn; also<a class="btn btn-success btn-sm" href="">Info</a>. Der Wert fürhreffindet sich jeweils unter demlink-Eintrag für jede Stadt instaedte.json. - für das Bild verwenden Sie den
bild-Link ausstaedte.jsonalssrc. Geben Sie auch dem Attributalteinen Wert (diestadtausstaedte.json). - die Tabelle sieht dann so aus:

- für jede neu entstehende Tabellenzeile müssen Sie fünf neue
- Bei Eingabe in das Textfeld von
Filterwird bei jedem Zeichen, das eingegeben wird, die FunktioncreateTable()aufgerufen (sieheoninput="createTable()"). Es sollen nun nur noch die Städte angezeigt werden, deren Stadtnamen oder deren Gründungsjahr zur Eingabe passt.- Wird also z.B.
breingegeben, dann erscheinen nur die Städte, die mitBrbeginnen (Groß- und Kleinschreibung egal, siehetoLowerCase()):
- Wird also z.B.
12eingegeben, dann erscheinen nur die Städte, deren Gründungsjahr mit12beginnt:
- Tipp: Sie laufen in einer Schleife durch das Array, um alle Städte auszulesen. Fügen Sie darin eine Bedingung ein, dass Sie nur die Städte der Tabelle hinzufügen, die der Filter-Eingabe entsprechen.
- Wird also z.B.
Übung 6¶
Übungsaufgabe 6 (Angular - Komponenten)
- Erstellen Sie ein neues Angular-Projekt
Uebung6(siehe hier). - Erstellen Sie mindestens folgende Komponenten:
header,nav,footer,tableundform. -
Gestalten Sie
header,navundfooterso, dass es ungefähr so aussieht:
Diese drei Komponenten sollen mittels Komponentenselektoren in die
AppComponenteingebunden werden. -
Erstellen Sie für die
TableComponentdie Routereadund für dieFormComponentdie Routecreate, so dass fürlocalhost:4200/createungefähr folgende Ansicht erscheint:
Diese Komponente enthält ein Formular. Für
localhost:4200/readerscheint ungefähr folgende Ansicht:
Diese Komponente enthält eine Tabelle. Es ist nur der Tabellenkopf mit den Spaltenüberschriften zu sehen.
-
In der nächsten Übung befüllen wir die Tabelle mithilfe eines Services.
Übung 7¶
Übungsaufgabe 7 (JSON, Templates, Service)
- Nutzen Sie Ihre Implementierung aus
Uebung6- wenn nicht, erstellen Sie ein neues Angular-ProjektUebung7(siehe hier). -
Erstellen Sie im
public-Ordner eine Dateimembers.jsonmit folgendem Inhalt:assets/members.json
[{ "forename": "Catherine", "surname": "Williams", "email": "cwilliamsl@360.cn" }, { "forename": "Adam", "surname": "Anderson", "email": "aanderson8@google.fr" }, { "forename": "Susan", "surname": "Andrews", "email": "sandrewsn@google.co.jp" }, { "forename": "Catherine", "surname": "Andrews", "email": "candrewsp@noaa.gov" }, { "forename": "Alan", "surname": "Bradley", "email": "abradley1c@globo.com" }, { "forename": "Anne", "surname": "Brooks", "email": "abrooks16@bravesites.com" }, { "forename": "Russell", "surname": "Brown", "email": "rbrownq@nifty.com" }, { "forename": "Ryan", "surname": "Burton", "email": "rburton18@foxnews.com" }, { "forename": "Roy", "surname": "Campbell", "email": "rcampbell1@geocities.com" }, { "forename": "Russell", "surname": "Campbell", "email": "rcampbell17@eventbrite.com" }, { "forename": "Bonnie", "surname": "Coleman", "email": "bcoleman11@fc2.com" }, { "forename": "Ernest", "surname": "Coleman", "email": "ecoleman15@businessweek.com" }, { "forename": "Richard", "surname": "Cruz", "email": "rcruz7@unc.edu" }, { "forename": "Sean", "surname": "Cruz", "email": "scruz10@answers.com" }, { "forename": "Rebecca", "surname": "Cunningham", "email": "rcunninghamd@mac.com" }, { "forename": "Margaret", "surname": "Evans", "email": "mevansh@pcworld.com" }, { "forename": "Jeffrey", "surname": "Ford", "email": "jford14@cnet.com" }, { "forename": "Andrea", "surname": "Gardner", "email": "agardnerv@woothemes.com" }, { "forename": "Deborah", "surname": "George", "email": "dgeorge6@furl.net" }, { "forename": "Sean", "surname": "Gibson", "email": "sgibsony@alexa.com" }, { "forename": "Virginia", "surname": "Graham", "email": "vgrahamk@aol.com" }, { "forename": "Steven", "surname": "Hamilton", "email": "shamiltonu@state.tx.us" }, { "forename": "Virginia", "surname": "Hawkins", "email": "vhawkinsf@ehow.com" }, { "forename": "Edward", "surname": "Hicks", "email": "ehicksc@pcworld.com" }, { "forename": "Mark", "surname": "Johnson", "email": "mjohnsonj@hostgator.com" }, { "forename": "Ruth", "surname": "Jordan", "email": "rjordan1a@smugmug.com" }, { "forename": "Antonio", "surname": "Kim", "email": "akim4@odnoklassniki.ru" }, { "forename": "Jennifer", "surname": "Marshall", "email": "jmarshallt@gnu.org" }, { "forename": "Eric", "surname": "Matthews", "email": "ematthews5@independent.co.uk" }, { "forename": "Raymond", "surname": "Mcdonald", "email": "rmcdonald2@ihg.com" }, { "forename": "Eric", "surname": "Miller", "email": "emillere@creativecommons.org" }, { "forename": "Jonathan", "surname": "Morales", "email": "jmoralesa@ovh.net" }, { "forename": "Marie", "surname": "Morgan", "email": "mmorganb@cloudflare.com" }, { "forename": "Amanda", "surname": "Nelson", "email": "anelson13@indiatimes.com" }, { "forename": "Lisa", "surname": "Olson", "email": "lolsonr@telegraph.co.uk" }, { "forename": "Alice", "surname": "Ortiz", "email": "aortizw@histats.com" }, { "forename": "Peter", "surname": "Phillips", "email": "pphillipss@1688.com" }, { "forename": "Matthew", "surname": "Porter", "email": "mporter9@europa.eu" }, { "forename": "Tammy", "surname": "Ray", "email": "trayx@weather.com" }, { "forename": "Mark", "surname": "Richardson", "email": "mrichardson1d@ihg.com" }, { "forename": "Joan", "surname": "Roberts", "email": "jroberts12@alibaba.com" }, { "forename": "Kathleen", "surname": "Rose", "email": "kroseg@pinterest.com" }, { "forename": "Steve", "surname": "Sanders", "email": "ssanders1b@wikispaces.com" }, { "forename": "Shirley", "surname": "Scott", "email": "sscottm@macromedia.com" }, { "forename": "Lillian", "surname": "Stephens", "email": "lstephens19@hugedomains.com" }, { "forename": "Nicole", "surname": "Thompson", "email": "nthompson3@admin.ch" }, { "forename": "Marie", "surname": "Thompson", "email": "mthompsonz@yelp.com" }, { "forename": "Alan", "surname": "Vasquez", "email": "avasquezo@miibeian.gov.cn" }, { "forename": "Mildred", "surname": "Watkins", "email": "mwatkins0@miibeian.gov.cn" }, { "forename": "Eugene", "surname": "Williams", "email": "ewilliamsi@deliciousdays.com" } ] -
Erstellen Sie einen Service
members.service.ts, in dem diemembers.jsonperfetch()eingelesen wird und der eine Funktion zur Verfügung stellt, die allemembersals Array zurückgibt. Erstellen Sie ein passendesMembers-Interface, um die Typsicherheit zu verbessern. -
Befüllen Sie mit den Daten aus
members.jsoneine Tabelle:
-
Implementieren Sie für das Suchfeld die Behandlung des
input-Ereignisses so, dass nur die Teilnehmerinnen in der Tabelle erscheinen, deren Vor- oder Nachnamen den Suchstring enthalten:
-
Alle Bilder sind nur Anregungen, kann gerne ganz anders aussehen. Gerne können Sie auch Bootstrap einbinden und verwenden (siehe z.B. hier).
Übung 8¶
Übungsaufgabe 8 (REST-API mit MongoDB)
- Erstellen Sie eine REST-API mit folgenden Endpunkten:
- Geben Sie am Anfang Folgendes im Terminal innerhalb Ihres Projekteordners ein (ohne die Kommentare):
- Vewenden Sie MongoDB als Datenbankmanagementsystem. Sie können sich entweder eine lokale Instanz installieren oder die Cloud-Lösung Atlas nutzen.
- Implementieren Sie obige CRUD-Funktionalitäten.
- Beachten Sie!: Es soll kein neuer
Userangelegt werden, wenn derusernamebereits verwendet wird und/oder wenn dieemailbereits verwendet wird:- Weder
usernamenochemailexitieren bereits: usernameexistiert bereits:emailexistiert bereits:
- Weder
GET /user/:namesucht nach demusername:- Das
SchemafürUserskann z.B. so aussehen:
| Endpunkt | Erläuterung |
|---|---|
GET /users | gebe alle user-Einträge zurück |
POST /users | erstelle einen neuen user |
GET /users/:name | gibt den user mit username == name zurück |
DELETE /users/:id | löscht den user mit _id == id |
PUT /users/:id | ändert Daten von user mit _id == id |
| Anweisung | Webseite |
|---|---|
mkdir Uebung8 | Ordner Uebung8erstellen |
npm init | Erstellt das Node.js-Projekt |
npm i express | express.js |
npm i dotenv | dotenv |
npm i mongoose | mongoose |
Übung 9¶
Übungsaufgabe 9 (Angular, Material Design und Formulare)
-
Erstellen Sie ein neues Angular-Projekt
Uebung9. -
Wechseln Sie in den
Uebung9-Ordner und fügen Sie dem Projekt mithilfe vonng add @angular/materialMaterial Design hinzu. Sie werden gefragt, ob Siematerialinstallieren wollen (Enter). Die anschließenden Fragen können Sie mitEnter(Theme),Y(Typography) undEnter(Animations) beantworten. -
Testen Sie, ob Material Design funktioniert, indem Sie in der
app.component.htmlalles löschen und stattdessen<mat-slide-toggle>Toggle me!</mat-slide-toggle>hinzufügen. In derapp.component.tsmuss dasMatSlideToggleModuleimportiert werden:import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, MatSlideToggleModule], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent { title = 'uebung9'; } -
Erzeugen Sie sich wie folgt die drei Komponenten
nav,formundtable(siehe Schematics): -
Erzeugen Sie sich auch eine einfache
home-Komponente (oder Sie probieren dafür dasDashboard-Schema aus). -
Fügen Sie in die
app.component.htmlden Aufruf derNavComponentein: -
Vergessen Sie nicht, die
NavComponentin derapp.component.tszu importieren:import { Component } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { NavComponent } from './nav/nav.component'; @Component({ selector: 'app-root', standalone: true, imports: [RouterOutlet, NavComponent], templateUrl: './app.component.html', styleUrl: './app.component.css' }) export class AppComponent { title = 'uebung9'; } -
Starten Sie das Projekt mit
ng serve. Je nachdem, welches Farbschema Sie gewählt haben, sieht die Seite nun ungefähr so aus:
Sie können Ihr Farbschema in der
angular.jsonimstyles-Array ändern (siehe hier) -
Erzeugen Sie für die drei Komponenten
home,tableundformdie Routen'',readundcreatedynamisch ein. Suchen Sie in dernav.component.htmlnach den Menüeinträgen und passen Sie das Menü so an, dass die drei Komponenten darüber aufgerufen werden können. -
Schauen Sie sich die
FormComponentund dieTableComponentgenauer an und versuchen Sie, die Komponenten an Ihre Bedürfnisse anzupassen.
folgende Erläuterungen, falls FormComponent nicht mit Schematics erzeugt wurde
-
In der
FormComponenterzeugen wir uns ein Formular. Schauen Sie sich dazu den Abschnitt Reactive Forms unter Angular.dev sowie die Abschnitte Form fields und Input unter Angular Material an.-
Die
FormComponentmussReactiveFormsModuleimimports-Array enthalten! -
Eingabefelder (
input) werden in Angular alsFormControl-Objekte defininiert, z.B.:export class FormComponent { username = new FormControl(''); password = new FormControl(''); email = new FormControl(''); role = new FormControl(''); }FormControlmuss aus@angular/formsimportiert werden. -
Die Verbindung zwischen View (
html) und Controller (ts) wird per[formControl]="username"hergestellt, z.B.:<label for="user-name">username</label> <input id="user-name" type="text" [formControl]="username" /> <label for="pwd">password</label> <input id="pwd" type="password" [formControl]="password" /> <label for="e-mail">email</label> <input id="e-mail" type="email" [formControl]="email" /> <label for="role">role</label> <select id="role" [formControl]="role"> <option value="">--Rolle auswählen--</option> <option value="user">user</option> <option value="admin">admin</option> </select> -
Unter Verwendung von Material Design werden die Elemente
<mat-form-field>,<mat-label>und die EigenschaftmatInputverwendet:<mat-form-field> <mat-label for="user-name">username</mat-label> <input matInput id="user-name" type="text" [formControl]="username" /> </mat-form-field> <br/> <mat-form-field> <mat-label for="pwd">password</mat-label> <input matInput id="pwd" type="password" [formControl]="password" /> </mat-form-field> <br /> <mat-form-field> <mat-label for="e-mail">email</mat-label> <input matInput id="e-mail" type="email" [formControl]="email" /> </mat-form-field> <br /> <mat-form-field> <mat-label for="role">role</mat-label> <select matNativeControl id="role" [formControl]="role"> <option value="">--Rolle auswählen--</option> <option value="user">user</option> <option value="admin">admin</option> </select> </mat-form-field>In der
form.component.tsmuss dazu dasimports-Array entsprechend befüllt werden: -
Den einzelnen
input-Elementen können Validatoren hinzugefügt werden, mit denen überprüft werden kann, ob die Eingabe den Anforderungen genügt. Dazu wird die KlasseValidatorsaus@angular/formsverwendet (siehe hier und hier), z.B.:username = new FormControl('', [Validators.required]); password = new FormControl('', [Validators.required, Validators.minLength(8)]); email = new FormControl('', [Validators.required, Validators.email]); role = new FormControl('', [Validators.required]); getErrorMessageUsername(){ if(this.username.hasError('required')) return 'Bitte ausfüllen'; else return ''; } getErrorMessagePassword(){ if(this.password.hasError('required')) return 'Bitte ausfüllen'; else if(this.password.hasError('minlength')) return 'Mindestens 8 Zeichen'; else return ''; } getErrorMessageEmail(){ if(this.email.hasError('required')) return 'Bitte ausfüllen'; else if(this.email.hasError('email')) return 'Keine gültige E-Mail-Adresse'; else return ''; } getErrorMessageRole(){ if(this.role.hasError('required')) return 'Bitte ausfüllen'; else return ''; }Die
getErrorMessage-Funktionen können dann z.B. so im HTML-Code verwendet werden:<mat-form-field class="wide-width"> <mat-label for="user-name">username</mat-label> <input matInput id="user-name" type="text" [formControl]="username" /> @if (username.invalid) { <mat-error>{{getErrorMessageUsername()}}</mat-error> } </mat-form-field> <br/> <mat-form-field class="wide-width"> <mat-label for="pwd">password</mat-label> <input matInput id="pwd" type="password" [formControl]="password" /> @if (password.invalid) { <mat-error>{{getErrorMessagePassword()}}</mat-error> } </mat-form-field> <br /> <mat-form-field class="wide-width"> <mat-label for="e-mail">email</mat-label> <input matInput id="e-mail" type="email" [formControl]="email" /> @if (email.invalid) { <mat-error>{{getErrorMessageEmail()}}</mat-error> } </mat-form-field> <br /> <mat-form-field class="wide-width"> <mat-label for="role">role</mat-label> <select matNativeControl id="role" [formControl]="role" placeholder="role"> <option value="user">user</option> <option value="admin">admin</option> </select> @if (role.invalid) { <mat-error>{{getErrorMessageRole()}}</mat-error> } </mat-form-field> -
Button hinzufügen: Für Matrial Design Buttons siehe hier, z.B.:
Dazu muss
MatButtonModulein dasimports-Array vonform.component.tseingefügt werden. -
Der Button ist so lange
disabled, so lange das Formular nicht korrekt ausgefüllt ist, d.h.formInvalid()liefert so lange eintruezurück, so lange (mindestens) einer der Fehler auftritt, der eine Error-Message erzeugt (siehe oben). Schreiben Sie die FunktionformInvalid()entsprechend. -
Bei Klick auf den Button (wenn er
enabledist), wird die Funktionregister()aufgerufen. Implementieren Sie diese Funktion so, dass ein Objekt der Art
auf die Konsole ausgegeben wird.
-
In Übung 10 werden wir die so erzeugten Objekte an das Backend senden und in die Datenbank speichern. Außerdem befüllen wir dann die
TableComponentmit Objekten aus der Datenbank.
-
Übung 10¶
Übungsaufgabe 10 (Frontend-Backend-Anbindung)
-
Starten Sie das Backend aus Übung 8.
-
Nutzen Sie das Frontend aus Übung 9 und erweitern es wie folgt:
-
Binden Sie in die
app.config.tsdas HttpClientModule ein:import { ApplicationConfig, importProvidersFrom } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { HttpClientModule } from '@angular/common/http'; export const appConfig: ApplicationConfig = { providers: [provideRouter(routes), importProvidersFrom(HttpClientModule)] }; -
Erstellen Sie sich einen
Backend-Service und einUser-Interface mithilfe der Angular CLI: -
Definieren Sie im
User-Interface die Eigenschaftenusername, password, email, role(allesstrings). -
Definieren Sie sich im
Backend-Service Funktionen für die Anbindung der Backend-Endpunkte (GET /users,POST /users,GET /users/:name,DELETE /users/:idundPUT / users/:id). Beachten Sie, dass jeweils ein Observable zurückgegeben wird, z.B.:import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { User } from './user'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class BackendService { backendUrl = 'http://localhost:4000'; constructor(private http: HttpClient) { } getAllUsers(): Observable<User[]> { let endpoint = '/users'; return this.http.get<User[]>(this.backendUrl + endpoint); } deleteOneMember(id: string): Observable<any> { let endpoint = '/users'; return this.http.delete<any>(this.backendUrl + endpoint + "/" + id); } createNewUser(user: User): Observable<User> { let endpoint = '/users'; return this.http.post<User>(this.backendUrl + endpoint, user); } } -
Binden Sie in die
Register-Komponente denBackend-Service ein, z.B.private bs = inject(BackendService);. Lesen Sie alle Werte aus dem Registrierungsformular aus und erzeugen sich damit ein neuesuser-Objekt. Rufen Sie die FunktioncreateNewUser(user)aus demBackend-Service auf, z.B.:this.bs.createNewUser(user).subscribe({ next: (response) => console.log('response', response), error: (err) => console.log(err), complete: () => console.log('register completed') });Prüfen Sie, ob die Daten in die Datenbank gespeichert werden.
-
Binden Sie in die
Table-Komponente denBackend-Service ein und erstellen sich dort einereadAll()-Funktion, in der diegetAllUsers()-Funktion desBackend-Services aufgerufen wird.- Befüllen Sie mit der Response ein
users-Array. - Rufen Sie in der
ngOnInit()-Funktion der Komponente diereadAll()-Funktion auf (die Komponente muss dazuOnInitimplementieren). - Lesen Sie in einer Tabelle in der
table.component.htmlalle User aus demusers-Array aus. - Richten Sie in der Tabelle eine Spalte
Deleteein, deren Einträge aus Buttons bestehen. Für das Klick-Ereignis soll einedelete(id)-Funktion aufgerufen werden, die den Eintrag aus der Datenbank löscht. Rufen Sie in derdelete(id)-Funktion auch diereadAll()-Funktion erneut auf, damit dasusers-Array aktualisiert wird.
- Befüllen Sie mit der Response ein
-