Ü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!
eine mögliche Lösung für Übung 1 (HTML)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Übung 1</title>
</head>
<body>
<header>
<img title="FIW-Logo" src="./bilder/fiw.jpg" alt="FIW-Logo">
<span>WebTech2026</span>
</header>
<main>
<h1>Willkommen in WebTech!</h1>
<img src="./bilder/campus_wh.jpg" alt="Campus Wilhelminenhof">
<h3>Die ersten Schritte</h3>
<ul>
<li>
<a href="https://developer.mozilla.org/de/docs/Web/HTML">
HTML lernen
</a>
</li>
<li>
<a href="https://freiheit.f4.htw-berlin.de/webtech/uebungen/#ubung-1">Übung 1 absolvieren</a>
</li>
<li>
Lösung ins Git-Repository pushen
</li>
</ul>
<p>Hier findest Du meinen <a href="./unterseiten/plan.html">aktuellen Semesterplan</a></p>
<hr />
<p>Externe Links:
<a target="_blank" href="https://www.stw.berlin/mensen/einrichtungen/hochschule-f%C3%BCr-technik-und-wirtschaft-berlin/mensa-htw-wilhelminenhof.html">
Speiseplan
</a>
</p>
</main>
<footer>
<span>J. Freiheit</span>
</footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<header>
<img title="FIW-Logo" src="../bilder/fiw.jpg" alt="FIW-Logo">
<span>WebTech2026</span>
</header>
<main>
<h3>2. Semester</h3>
<table>
<thead>
<tr>
<th>Modulnr.</th>
<th>Modulname</th>
<th>LP</th>
</tr>
</thead>
<tbody>
<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>
</tbody>
</table>
<p>
<a href="../index.html">Zurück zur Startseite</a>
</p>
</main>
<footer>
<span>J. Freiheit</span>
</footer>
</body>
</html>
Ü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!
nach der Dienstagsübung 5.5.2026 (uebung_b)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Übung 2</title>
<link rel="stylesheet" href="./styles/mystyles.css">
</head>
<body>
<header>
<img title="FIW-Logo" src="./bilder/fiw.jpg" alt="FIW-Logo">
<span>WebTech2026</span>
</header>
<main id="indexmain">
<section>
<h1>Willkommen in WebTech!</h1>
<img src="./bilder/campus_wh.jpg" alt="Campus Wilhelminenhof" />
<h3>Die ersten Schritte</h3>
<ul>
<li>
<a href="https://developer.mozilla.org/de/docs/Web/HTML">
HTML lernen
</a>
</li>
<li title="https://freiheit.f4.htw-berlin.de/webtech/uebungen/#ubung-1">
<a href="https://freiheit.f4.htw-berlin.de/webtech/uebungen/#ubung-1">
Übung 1 absolvieren
</a>
</li>
<li>
Lösung ins Git-Repository pushen
</li>
</ul>
</section>
<aside>
<a href="./unterseiten/plan.html">
<img src="./bilder/plan.png" alt="semesterplan">
</a>
<a target="_blank" href="https://www.stw.berlin/mensen/einrichtungen/hochschule-f%C3%BCr-technik-und-wirtschaft-berlin/mensa-htw-wilhelminenhof.html">
<img src="./bilder/essen.png" alt="essen">
</a>
</p>
</aside>
</main>
<footer>
<span>J. Freiheit</span>
</footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Semesterplan</title>
<link rel="stylesheet" href="../styles/mystyles.css">
</head>
<body>
<header>
<img title="FIW-Logo" src="../bilder/fiw.jpg" alt="FIW-Logo">
<span>WebTech2026</span>
</header>
<main>
<h3>2. Semester</h3>
<!-- ein HTML-Kommentar -->
<table>
<thead>
<tr>
<th>Modulnr.</th>
<th>Modulname</th>
<th>LP</th>
</tr>
</thead>
<tbody>
<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>
</tbody>
</table>
<p><a href="../index.html">Zurück zur Startseite</a></p>
</main>
<footer>
J. Freiheit
</footer>
</body>
</html>
:root {
--htw-grau: #AFAFAF;
--htw-blau: #0082D1;
--htw-gruen: #76B900;
}
body {
font-family:Verdana, Geneva, Tahoma, sans-serif;
}
header {
background-color: var(--htw-grau);
color: white;
/*
display: grid;
grid-template-columns: 1fr 1fr;
*/
display: flex;
justify-content: space-between;
img {
width: 2em;
padding: 1%;
}
span {
/*text-align: right;*/
padding: 1%;
}
}
h1 {
color: var(--htw-blau);
}
h3 {
margin-left: 4%;
}
ul {
list-style: none;
}
ul>li {
border: 2px solid black;
border-radius: 1rem;
margin: 1%;
padding: 1%;
width: 30%;
a {
color: black;
text-decoration: none;
}
a:hover {
font-weight: bold;
}
}
ul>li:hover {
background-color: rgb(201, 201, 219);
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
a {
color: var(--htw-blau);
}
}
#indexmain {
background-color: rgb(226, 240, 226);
display: grid;
grid-template-columns: 4fr 1fr;
}
#indexmain>aside {
background-color: rgb(196, 226, 196);
text-align: center;
display: grid;
grid-template-rows: 1fr 1fr;
a {
margin: auto;
}
img {
width: 50%;
}
}
table {
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
border-collapse: collapse;
width: 60%;
thead tr {
background-color: var(--htw-gruen);
}
tbody tr:nth-child(even) {
background-color: rgb(230, 225, 225);
}
tbody tr:nth-child(odd) {
background-color: rgb(247, 215, 215);
}
tbody tr:hover {
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
}
td,th {
padding: 2%;
}
}
nach der Mittwochsübung 6.5.2026 (uebung_a)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Übung 2</title>
<link rel="stylesheet" href="./styles/mystyles.css">
</head>
<body>
<header>
<img title="FIW-Logo" src="./bilder/fiw.jpg" alt="FIW-Logo">
<span>WebTech2026</span>
</header>
<main id="indexmain">
<section>
<h1>Willkommen in WebTech!</h1>
<img src="./bilder/campus_wh.jpg" alt="Campus Wilhelminenhof">
<h3>Die ersten Schritte</h3>
<ul>
<li>
<a href="https://developer.mozilla.org/de/docs/Web/HTML">
HTML lernen
</a>
</li>
<li>
<a href="https://freiheit.f4.htw-berlin.de/webtech/uebungen/#ubung-1">Übung 1 absolvieren</a>
</li>
<li>
Lösung ins Git-Repository pushen
</li>
</ul>
</section>
<aside>
<a href="./unterseiten/plan.html">
<img src="./bilder/plan.png" alt="Plan">
</a>
<a target="_blank" href="https://www.stw.berlin/mensen/einrichtungen/hochschule-f%C3%BCr-technik-und-wirtschaft-berlin/mensa-htw-wilhelminenhof.html">
<img src="./bilder/essen.png" alt="Essen">
</a>
</aside>
</main>
<footer>
<span>J. Freiheit</span>
</footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Semesterplan</title>
<link rel="stylesheet" href="../styles/mystyles.css">
</head>
<body>
<header>
<img title="FIW-Logo" src="../bilder/fiw.jpg" alt="FIW-Logo">
<span>WebTech2026</span>
</header>
<main>
<h3>2. Semester</h3>
<table>
<thead>
<tr>
<th>Modulnr.</th>
<th>Modulname</th>
<th>LP</th>
</tr>
</thead>
<tbody>
<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>
</tbody>
</table>
<p>
<a href="../index.html">Zurück zur Startseite</a>
</p>
</main>
<footer>
<span>J. Freiheit</span>
</footer>
</body>
</html>
:root {
--htw-gruen: #76B900;
--htw-gruen-hell: #f9fcf4;
--htw-gruen-mittel: #edf5df;
--htw-blau: #0082D1;
--htw-grau: #AFAFAF;
}
body {
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
header {
background-color: var(--htw-grau);
display: grid;
grid-template-columns: 1fr 1fr;
img {
width: 3rem;
margin: 0.5rem;
}
span {
text-align: right;
margin: .5rem;
padding: .5rem;
}
}
main h1 {
color: var(--htw-blau);
}
main h3 {
margin-left: 2rem;
}
ul {
list-style-type: none;
li {
border: 2px solid black;
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px;
border-radius: .5rem;
margin-top: .4rem;
margin-bottom: .4rem;
margin-left: -.4rem;
padding: .4rem;
width: 30vw;
a {
text-decoration: none;
}
a:visited {
text-decoration: none;
color: var(--htw-blau);
}
a:link {
text-decoration: none;
color: red;
}
}
li:hover {
background-color: rgb(191, 206, 191);
border-color: green;
color: green;
font-weight: bold;
a:visited {
color: green;
}
a:link {
color: green;
}
}
}
#indexmain {
display: grid;
grid-template-columns: 4fr 1fr;
background-color: var(--htw-gruen-hell);
aside {
display: grid;
grid-template-rows: 1fr 1fr;
justify-items: center;
align-items: center;
background-color: var(--htw-gruen-mittel);
text-align: center;
}
img {
width: 40%;
}
}
table {
border-collapse: collapse;
thead {
background-color: var(--htw-gruen);
tr th {
padding: .5rem;
}
}
tbody {
tr:nth-child(even) {
background-color: rgb(187, 185, 185);
}
tr:nth-child(odd) {
background-color: rgb(237, 230, 230);
}
}
}
Ü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>
Eine mögliche Lösung für Übung 3
<!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>
<style>
header {
background-color: rgb(93, 119, 54);
color: white;
text-transform: uppercase;
text-align: center;
font-weight: bold;
padding: 2%;
margin-bottom: 2%;
}
.wrapper {
display: grid;
grid-template-columns: repeat(1, 1fr); /* 1 Spalte bis 800px Viewport-Breite */
column-gap: 2%;
row-gap: 2%;
}
.citycard {
display: grid;
grid-template-rows: 4fr 1fr;
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
}
.citycard:hover {
box-shadow: rgba(0, 0, 0, 0.3) 0px 19px 38px, rgba(0, 0, 0, 0.22) 0px 15px 12px;
background-color: rgb(238, 237, 235);
img {
height: 80%;
}
}
.cityimage {
text-align: center;
img {
height: 70%;
margin-top: 5%;
}
}
.cityname {
text-align: center;
font-weight: bold;
text-transform: uppercase;
padding-top: 3%;
font-size: 1.3em;
}
@media (min-width: 800px) {
.wrapper {
grid-template-columns: repeat(2, 1fr); /* 2 Spalten ab 800px bis 1200px Viewport-Breite */
}
}
@media (min-width: 1200px) {
.wrapper {
grid-template-columns: repeat(4, 1fr); /* 4 Spalten ab 1200px Viewport-Breite */
}
}
</style>
</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>
Eine mögliche Lösung für Übung 3 mit Bootstrap
<!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">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<title>Uebung 3 - Bootstrap</title>
</head>
<body class="container">
<header>
<h2>STÄDTE</h2>
</header>
<main>
<section class="row">
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/berlin.png" alt="Berlin">
<div class="card-text mt-auto text-center">
<p>Berlin</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/bernau.png" alt="Bernau">
<div class="card-text mt-auto text-center">
<p>Bernau</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/brandenburg.png" alt="Brandenburg">
<div class="card-text mt-auto text-center">
<p>Brandenburg</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/bremen.png" alt="Bremen">
<div class="card-text mt-auto text-center">
<p>Bremen</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/bremerhaven.png" alt="Bremerhaven">
<div class="card-text mt-auto text-center">
<p>Bremerhaven</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/madrid.png" alt="Madrid">
<div class="card-text mt-auto text-center">
<p>Madrid</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/magdeburg.png" alt="Magdeburg">
<div class="card-text mt-auto text-center">
<p>Magdeburg</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/mainz.png" alt="Mainz">
<div class="card-text mt-auto text-center">
<p>Mainz</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/mannheim.png" alt="Mannheim">
<div class="card-text mt-auto text-center">
<p>Mannheim</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/Marburg.png" alt="Marburg">
<div class="card-text mt-auto text-center">
<p>Marburg</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/newyork.png" alt="New York">
<div class="card-text mt-auto text-center">
<p>New York</p>
</div>
</div>
</div>
<div class="col-3 mb-3">
<div class="card h-100 shadow">
<img class="w-25 my-5 d-block mx-auto" src="./images/stockholm.png" alt="Stockholm">
<div class="card-text mt-auto text-center">
<p>Stockholm</p>
</div>
</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.
Eine mögliche Lösung für Übung 4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Übung 4</title>
<!-- <link rel="stylesheet" href="../styles/bootstrap/bootstrap.min.css"> -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
</head>
<body>
<main class="container">
<h1 class="m-5">Teilnehmerin Registrierung</h1>
<div class="row">
<div class="col-12 col-md-6 col-xl-3">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="firstName" placeholder="First name">
<label for="firstName">First name</label>
</div>
</div>
<div class="col-12 col-md-6 col-xl-3">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="lastName" placeholder="Last name">
<label for="lastName">Last name</label>
</div>
</div>
<div class="col-12 col-md-6 col-xl-3">
<div class="form-floating mb-3">
<input type="email" class="form-control" id="email" placeholder="E-Mail">
<label for="email">E-Mail</label>
</div>
</div>
<div class="col-12 col-md-6 col-xl-3">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="ipaddress" placeholder="IP-Address">
<label for="ipaddress">IP-Address</label>
</div>
</div>
<div class="col-6">
<button type="cancel" class="btn btn-secondary btn-lg w-100">Abbrechen</button>
</div>
<div class="col-6">
<button type="submit" class="btn btn-success btn-lg w-100">Registrieren</button>
</div>
</div>
</main>
</body>
</html>
Ü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).
Eine mögliche Lösung für Übung 4a
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<title>Übung 4a</title>
</head>
<body>
<main class="container">
<h1 class="mt-5">Teilnehmerin Registrierung</h1>
<form>
<div class="row">
<div class="col-12 col-md-6 col-lg-3">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="firstNameID" placeholder="First name" required>
<label for="firstNameID">First name</label>
<div class="valid-feedback">
Toll!
</div>
<div class="invalid-feedback">
Vorname erforderlich!
</div>
</div>
</div>
<div class="col-12 col-md-6 col-lg-3">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="lastNameID" placeholder="Last name" required>
<label for="lastNameID">Last name</label>
</div>
</div>
<div class="col-12 col-md-6 col-lg-3">
<div class="form-floating mb-3">
<input type="email" class="form-control" id="emailID" placeholder="name@example.com" required>
<label for="emailID">Email address</label>
</div>
</div>
<div class="col-12 col-md-6 col-lg-3">
<div class="form-floating mb-3">
<input type="text" class="form-control" id="ipaddressID" placeholder="IP-Address" required>
<label for="ipaddressID">IP-Address</label>
</div>
</div>
</div>
<div class="row">
<div class="col-12 col-sm-3">
<button class="btn btn-secondary btn-lg w-100 mb-3" type="cancel">Abbrechen</button>
</div>
<div class="col-12 col-sm-3">
<button class="btn btn-success btn-lg w-100" onclick="register()" type="submit">Registrieren</button>
</div>
</div>
</form>
<h3 class="mt-5">Eingegebene Werte</h3>
<ul id="output" class="list-group">
</ul>
</main>
</body>
<script>
function register() {
event.preventDefault() // wenn form und submit-Button, dann notwendig!!!
console.log('Registrieren-Button geklickt')
// Eingaben auslesen
let firstNameElement = document.querySelector('#firstNameID');
console.log(firstNameElement)
let firstNameValue = firstNameElement.value;
console.log(firstNameValue)
let lastNameElement = document.querySelector('#lastNameID')
let lastNameValue = lastNameElement.value;
let emailElement = document.querySelector('#emailID')
let emailValue = emailElement.value;
let ipaddressElement = document.querySelector('#ipaddressID')
let ipaddressValue = ipaddressElement.value;
// Eingaben auf Konsole ausgeben
console.log('firstNameValue : ', firstNameValue)
console.log('lastNameValue : ', lastNameValue)
console.log('emailValue : ', emailValue)
console.log('ipaddressValue : ', ipaddressValue)
/*
if(firstNameValue == "") {
firstNameElement.classList.add('is-invalid')
firstNameElement.classList.remove('is-valid')
} else {
firstNameElement.classList.add('is-valid')
firstNameElement.classList.remove('is-invalid')
}
*/
let inputAll = document.querySelectorAll('input')
console.log(inputAll)
inputOk = true;
for(let index = 0; index < inputAll.length; index++)
{
if(inputAll[index].value == "") {
inputOk = false;
inputAll[index].classList.add('is-invalid')
inputAll[index].classList.remove('is-valid')
} else {
inputAll[index].classList.add('is-valid')
inputAll[index].classList.remove('is-invalid')
}
}
for(let input of inputAll) {
console.log('inputs : ', input)
}
let outputListe = document.querySelector('#output')
let h3 = document.querySelector('h3')
if(inputOk) {
h3.textContent = "Eingegebene Werte"
h3.style.color = "black";
outputListe.innerHTML = `<li class="list-group-item"> Vorname: ${firstNameValue}</li>
<li class="list-group-item"> Nachname: ${lastNameValue}</li>
<li class="list-group-item"> E-Mail: ${emailValue}</li>
<li class="list-group-item"> IP-Adresse: ${ipaddressValue}</li>`
}
else {
h3.textContent = "Alle Werte erforderlich!"
h3.style.color = "red";
}
}
</script>
</html>
Übung 5¶
Übungsaufgabe 5 (JavaScript, DOM)
- Laden Sie die Datei uebung5.zip herunter, entpacken Sie sie und schieben den Ordner
uebung5in 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
-