Compare commits

..

13 Commits

Author SHA1 Message Date
590b6e86e4 fix 2025-12-06 12:19:06 +01:00
37b17c4f95 fix 2025-12-06 12:14:57 +01:00
89e8e7371c migrate app 2025-12-06 11:51:10 +01:00
00a33b4cd2 migrate display-html 2025-12-06 11:41:31 +01:00
4c63b5927d migrate create-auto 2025-12-06 11:40:28 +01:00
3b983ebbf4 migrate project 2025-12-06 11:38:19 +01:00
314a581378 fix angular/cli config 2025-12-06 11:34:42 +01:00
f317ae2f4d wip 2025-12-06 10:38:18 +01:00
af5da29daf uebung-6 2025-12-06 08:46:55 +01:00
a8a8ec9779 clean up and install angular cli 2025-11-22 13:24:40 +01:00
210dd12663 ignore jetty.base directory 2025-11-22 12:43:38 +01:00
761eb6f4a6 working jetty config 2025-11-22 12:42:42 +01:00
b98cbf3615 uebung-5 2025-11-22 09:04:51 +01:00
40 changed files with 14514 additions and 56 deletions

1
.envrc
View File

@@ -1 +0,0 @@
use flake

7
.gitignore vendored
View File

@@ -40,3 +40,10 @@ build/
### nix / direnv ### nix / direnv
.direnv .direnv
result result
### jetty
**/.jetty/home
**/.jetty/base
### Angualr Demo ###
**/node_modules

17
demo/.editorconfig Normal file
View File

@@ -0,0 +1,17 @@
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.ts]
quote_type = single
ij_typescript_use_double_quotes = false
[*.md]
max_line_length = off
trim_trailing_whitespace = false

43
demo/.gitignore vendored Normal file
View File

@@ -0,0 +1,43 @@
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
__screenshots__/
# System files
.DS_Store
Thumbs.db

59
demo/README.md Normal file
View File

@@ -0,0 +1,59 @@
# Demo
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.0.2.
## Development server
To start a local development server, run:
```bash
ng serve
```
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
## Code scaffolding
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
```bash
ng generate component component-name
```
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
```bash
ng generate --help
```
## Building
To build the project run:
```bash
ng build
```
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
## Running unit tests
To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command:
```bash
ng test
```
## Running end-to-end tests
For end-to-end (e2e) testing, run:
```bash
ng e2e
```
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
## Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.

73
demo/angular.json Normal file
View File

@@ -0,0 +1,73 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "npm"
},
"newProjectRoot": "projects",
"projects": {
"demo": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular/build:application",
"options": {
"browser": "src/main.ts",
"tsConfig": "tsconfig.app.json",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.css"
]
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kB",
"maximumError": "1MB"
},
{
"type": "anyComponentStyle",
"maximumWarning": "4kB",
"maximumError": "8kB"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "demo:build:production"
},
"development": {
"buildTarget": "demo:build:development"
}
},
"defaultConfiguration": "development"
},
"test": {
"builder": "@angular/build:unit-test"
}
}
}
}
}

9338
demo/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

43
demo/package.json Normal file
View File

@@ -0,0 +1,43 @@
{
"name": "demo",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"prettier": {
"printWidth": 100,
"singleQuote": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
}
]
},
"private": true,
"packageManager": "npm@11.6.2",
"dependencies": {
"@angular/common": "^21.0.0",
"@angular/compiler": "^21.0.0",
"@angular/core": "^21.0.0",
"@angular/forms": "^21.0.0",
"@angular/platform-browser": "^21.0.0",
"@angular/router": "^21.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0"
},
"devDependencies": {
"@angular/build": "^21.0.2",
"@angular/cli": "^21.0.2",
"@angular/compiler-cli": "^21.0.0",
"jsdom": "^27.1.0",
"typescript": "~5.9.2",
"vitest": "^4.0.8"
}
}

BIN
demo/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

18
demo/src/app/Auto.ts Normal file
View File

@@ -0,0 +1,18 @@
export class Auto {
constructor(
private _hersteller: string,
private _typ: string,
private _kennzeichen: string,
) {
}
get typ(): string { return this._typ; }
set typ(typ: string) { this._typ = typ; }
get hersteller(): string { return this._hersteller; }
set hersteller(hersteller: string) { this._hersteller = hersteller; }
get kennzeichen(): string { return this._kennzeichen; }
set kennzeichen(kennzeichen: string) { this._kennzeichen = kennzeichen; }
}

View File

@@ -0,0 +1,11 @@
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideRouter(routes)
]
};

210
demo/src/app/app.html Normal file
View File

@@ -0,0 +1,210 @@
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * Delete the template below * * * * * * * * * -->
<!-- * * * * * * * to get started with your project! * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<style>
:host {
--bright-blue: oklch(51.01% 0.274 263.83);
--electric-violet: oklch(53.18% 0.28 296.97);
--french-violet: oklch(47.66% 0.246 305.88);
--vivid-pink: oklch(69.02% 0.277 332.77);
--hot-red: oklch(61.42% 0.238 15.34);
--orange-red: oklch(63.32% 0.24 31.68);
--gray-900: oklch(19.37% 0.006 300.98);
--gray-700: oklch(36.98% 0.014 302.71);
--gray-400: oklch(70.9% 0.015 304.04);
--red-to-pink-to-purple-vertical-gradient: linear-gradient(
180deg,
var(--orange-red) 0%,
var(--vivid-pink) 50%,
var(--electric-violet) 100%
);
--red-to-pink-to-purple-horizontal-gradient: linear-gradient(
90deg,
var(--orange-red) 0%,
var(--vivid-pink) 50%,
var(--electric-violet) 100%
);
--pill-accent: var(--bright-blue);
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
"Segoe UI Symbol";
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
h1 {
font-size: 3.125rem;
color: var(--gray-900);
font-weight: 500;
line-height: 100%;
letter-spacing: -0.125rem;
margin: 0;
font-family: "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
"Segoe UI Symbol";
}
p {
margin: 0;
color: var(--gray-700);
}
main {
width: 100%;
min-height: 100%;
display: flex;
justify-content: center;
align-items: center;
padding: 1rem;
box-sizing: inherit;
position: relative;
}
.angular-logo {
max-width: 9.2rem;
}
.content {
display: flex;
justify-content: space-around;
width: 100%;
max-width: 700px;
margin-bottom: 3rem;
}
.content h1 {
margin-top: 1.75rem;
}
.content p {
margin-top: 1.5rem;
}
.divider {
width: 1px;
background: var(--red-to-pink-to-purple-vertical-gradient);
margin-inline: 0.5rem;
}
.pill-group {
display: flex;
flex-direction: column;
align-items: start;
flex-wrap: wrap;
gap: 1.25rem;
}
.pill {
display: flex;
align-items: center;
--pill-accent: var(--bright-blue);
background: color-mix(in srgb, var(--pill-accent) 5%, transparent);
color: var(--pill-accent);
padding-inline: 0.75rem;
padding-block: 0.375rem;
border-radius: 2.75rem;
border: 0;
transition: background 0.3s ease;
font-family: var(--inter-font);
font-size: 0.875rem;
font-style: normal;
font-weight: 500;
line-height: 1.4rem;
letter-spacing: -0.00875rem;
text-decoration: none;
white-space: nowrap;
}
.pill:hover {
background: color-mix(in srgb, var(--pill-accent) 15%, transparent);
}
.pill-group .pill:nth-child(6n + 1) {
--pill-accent: var(--bright-blue);
}
.pill-group .pill:nth-child(6n + 2) {
--pill-accent: var(--electric-violet);
}
.pill-group .pill:nth-child(6n + 3) {
--pill-accent: var(--french-violet);
}
.pill-group .pill:nth-child(6n + 4),
.pill-group .pill:nth-child(6n + 5),
.pill-group .pill:nth-child(6n + 6) {
--pill-accent: var(--hot-red);
}
.pill-group svg {
margin-inline-start: 0.25rem;
}
.social-links {
display: flex;
align-items: center;
gap: 0.73rem;
margin-top: 1.5rem;
}
.social-links path {
transition: fill 0.3s ease;
fill: var(--gray-400);
}
.social-links a:hover svg path {
fill: var(--gray-900);
}
@media screen and (max-width: 650px) {
.content {
flex-direction: column;
width: max-content;
}
.divider {
height: 1px;
width: 100%;
background: var(--red-to-pink-to-purple-horizontal-gradient);
margin-block: 1.5rem;
}
}
</style>
<main class="main">
<div class="content">
<div class="uebung-6">
<app-create-auto (autoInitializedEvent)="setAuto($event)"></app-create-auto>
<div> Typ: {{ auto?.typ ?? "N/A" }} </div>
<div> Hersteller: {{ auto?.hersteller ?? "N/A" }} </div>
<div> Kennzeichen: {{ auto?.kennzeichen ?? "N/A" }} </div>
</div>
<div class="praktikum-6">
<app-display-html html="<b>initialer text</b>"></app-display-html>
</div>
</div>
</main>
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content above * * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<router-outlet />

View File

@@ -0,0 +1,3 @@
import { Routes } from '@angular/router';
export const routes: Routes = [];

23
demo/src/app/app.spec.ts Normal file
View File

@@ -0,0 +1,23 @@
import { TestBed } from '@angular/core/testing';
import { App } from './app';
describe('App', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [App],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it('should render title', async () => {
const fixture = TestBed.createComponent(App);
await fixture.whenStable();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, demo');
});
});

20
demo/src/app/app.ts Normal file
View File

@@ -0,0 +1,20 @@
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { CreateAutoComponent } from './create-auto/create-auto';
import { DisplayHtmlComponent } from './display-html/display-html';
import { Auto } from './Auto';
@Component({
selector: 'app-root',
imports: [RouterOutlet, CreateAutoComponent, DisplayHtmlComponent],
templateUrl: './app.html',
styleUrl: './app.css'
})
export class App {
protected readonly title = signal('demo');
auto?: Auto;
setAuto(auto: Auto) {
this.auto = auto;
}
}

View File

View File

@@ -0,0 +1 @@
<button (click)="createAuto()">Auto erstellen</button>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { CreateAuto } from './create-auto';
describe('CreateAuto', () => {
let component: CreateAuto;
let fixture: ComponentFixture<CreateAuto>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [CreateAuto]
})
.compileComponents();
fixture = TestBed.createComponent(CreateAuto);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,17 @@
import { Component, Output, EventEmitter } from '@angular/core';
import { Auto } from '../Auto';
@Component({
selector: 'app-create-auto',
imports: [],
templateUrl: './create-auto.html',
styleUrl: './create-auto.css',
})
export class CreateAutoComponent {
@Output() autoInitializedEvent: EventEmitter<Auto> = new EventEmitter<Auto>();
createAuto() {
var auto = new Auto("BMW", "e36", "DE-RS-7331");
this.autoInitializedEvent.emit(auto);
}
}

View File

@@ -0,0 +1,4 @@
<div>
<p innerHtml="{{ html }}"></p>
<button (click)="updateHtml()">Update Html</button>
</div>

View File

@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DisplayHtml } from './display-html';
describe('DisplayHtml', () => {
let component: DisplayHtml;
let fixture: ComponentFixture<DisplayHtml>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DisplayHtml]
})
.compileComponents();
fixture = TestBed.createComponent(DisplayHtml);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,15 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-display-html',
imports: [],
templateUrl: './display-html.html',
styleUrl: './display-html.css',
})
export class DisplayHtmlComponent {
html: string = '';
updateHtml() {
this.html = "<i>neuer text ???</i>";
}
}

13
demo/src/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Demo</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>

6
demo/src/main.ts Normal file
View File

@@ -0,0 +1,6 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));

1
demo/src/styles.css Normal file
View File

@@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

15
demo/tsconfig.app.json Normal file
View File

@@ -0,0 +1,15 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"include": [
"src/**/*.ts"
],
"exclude": [
"src/**/*.spec.ts"
]
}

33
demo/tsconfig.json Normal file
View File

@@ -0,0 +1,33 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"compileOnSave": false,
"compilerOptions": {
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"isolatedModules": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "ES2022",
"module": "preserve"
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
},
"files": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

15
demo/tsconfig.spec.json Normal file
View File

@@ -0,0 +1,15 @@
/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */
/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"vitest/globals"
]
},
"include": [
"src/**/*.d.ts",
"src/**/*.spec.ts"
]
}

View File

@@ -9,12 +9,63 @@
\begin{exercises} \begin{exercises}
\item Worum handelt es sich bei Facelets und welche Vorteile bietet die Verwendung von Facelets? \item Worum handelt es sich bei Facelets und welche Vorteile bietet die Verwendung von Facelets?
Facelets sind eine Tag Library, die zusätzliche Tags bereitstellt.
Mit Facelets können Templates erstellt werden, oder wiederholte Ausgaben von html deklerativ in xml erstellt werden.
\item Wie können Templates mit Facelets erstellt bzw. verwendet werden? \item Wie können Templates mit Facelets erstellt bzw. verwendet werden?
In Templates wird der generelle Aufbau einer Seite definiert. Dies erfolgt wie in einer normale xhtml Seite, nur mit Platzhaltern (\texttt{<ui:insert>}):
\begin{xmlCode}
...
<body>
<ui:insert name="header">
<ui:include src="default-header.xhtml">
</ui:insert>
<ui:insert name="content">
</ui:insert>
<ui:insert name="footer">
</ui:insert>
</body>
...
\end{xmlCode}
Verwendet wird ein Template dann, in dem man mit \texttt{<ui:composition>} das template angibt, und mit ui:define die Platzhalter fŭllt:
\begin{xmlCode}
<ui:composition template="template.xhtml">
<ui:define name="content">
<p>hello world</p>
</ui:define>
</ui:composition>
\end{xmlCode}
\item Worum handelt es sich bei PrimeFaces? \item Worum handelt es sich bei PrimeFaces?
PrimeFaces stellen eine Komponentenbibliothek dar, die Komponenten mit AJAX-Unterstützung anbieten.
\item Welcher Namespace wird für die Verwendung von PrimeFaces benutzt? \item Welcher Namespace wird für die Verwendung von PrimeFaces benutzt?
\texttt{xmlns:p}
\item Wie kann per Ajax auf die Eingabe eines Tastenklicks reagiert werden? \item Wie kann per Ajax auf die Eingabe eines Tastenklicks reagiert werden?
Indem man auf das \textit{keydown} Event reagiert:
\begin{xmlCode}
<p:ajax event="keydown" .../>
\end{xmlCode}
\item Zählen Sie vier PrimeFaces-Komponenten auf und geben deren Funktion an. \item Zählen Sie vier PrimeFaces-Komponenten auf und geben deren Funktion an.
\begin{itemize}
\item \texttt{<p:autocomplete>}: Ermöglicht completion-Vorschläge für ein Input-Feld
\item \texttt{<p:calendar>}: Kalendar-Datum Eingabe-Element
\item \texttt{<p:gmap>}: Google-Maps Element
\item \texttt{<p:textEditor>}: Ein Wysiwyg Texteditor
\end{itemize}
\item Erstellen Sie eine JSF-Seite, die eine Klappliste anzeigt in der einer der Werte „Farben“, „Zahlen“ oder „Buchstaben“ ausgewählt werden kann. Darunter befindet sich eine Klappliste die zunächst nur den Inhalt „---“ hat. Nach einer Auswahl in der ersten Klappliste soll ein AJAX-Request generiert werden, der den Inhalt der zweiten Klappliste setzt (denken Sie sich zu den in Klappliste 1 auswählbaren Werten passende Werte aus). \item Erstellen Sie eine JSF-Seite, die eine Klappliste anzeigt in der einer der Werte „Farben“, „Zahlen“ oder „Buchstaben“ ausgewählt werden kann. Darunter befindet sich eine Klappliste die zunächst nur den Inhalt „---“ hat. Nach einer Auswahl in der ersten Klappliste soll ein AJAX-Request generiert werden, der den Inhalt der zweiten Klappliste setzt (denken Sie sich zu den in Klappliste 1 auswählbaren Werten passende Werte aus).
\end{exercises} \end{exercises}
\end{document} \end{document}

248
docs/uebungen/uebung-6.tex Normal file
View File

@@ -0,0 +1,248 @@
\documentclass{uebung}
\author{Linus Nagel}
\chapter{5}
\begin{document}
\maketitle
\begin{exercises}
\item Worin bestehen die Vorteile von Single Page Applications?
\begin{itemize}
\item Geringerer Web Traffic: Höhere Performance durch eine geringere Datenmenge bei der Kommunikation: Mobile Devices profitieren von der Reduzierung des notwendigen online Volumens.
\item Kein 'Flackern' der Seite, da sie nicht jedes Mal komplett neu geladen wird.
\item Durch die direkte Reaktion des Frontends auf Bedienereingaben besteht insgesamt eine bessere User Experience als bei klassischen Web Applications.
\item Solange keine Informationen nachgeladen werden müssen, wird ein Offline-Betrieb ermöglicht.
\end{itemize}
\item Erläutern Sie die Vorteile von TypeScript gegenüber JavaScript.
\begin{itemize}
\item Statische Typisierung
\item TypeScript ermöglicht die Nutzung vieler aus der Objektorientierung bekannten Sprachkonstrukte
\item TypeScript ermöglicht die Verwendung von Lambda-Ausdrücken und Dekoratoren (in Java Annotation genannt).
\end{itemize}
\item Wie werden in TypeScript Klassen erstellt?
z.B. so:
\begin{minted}{ts}
class Person {
constructor(private _name: string) {
}
get name(): string {
return this._name;
}
set name(name: string) {
this._name = name;
}
}
\end{minted}
\item Wie werden in TypeScript Konstruktoren erstellt? Können mehrere Konstruktoren erstellt werden?
Es kann nur ein constructor erstellt werden. Dieser kann dafür dann aber default-Werte haben, damit der caller nicht alle Attribute setzen muss:
\begin{minted}{ts}
class Person {
constructor(private _name: string = "Max Mustermann") {
}
}
\end{minted}
\item Wie werden in TypeScript Methoden erstellt?
\begin{minted}{ts}
getStuff(param: paramType = paramDefault): StuffType {
...
return ...
}
\end{minted}
\item Worum handelt es sich, wenn von einem ist Dekorator gesprochen wird?
Schlüsselwörter, die mit dem Zeichen @ beginnen. Durch in runden Klammern folgende Attribute können Dekoratoren noch weitere Konfigurationsdaten aufnehmen.
\item Beschreiben Sie den Aufbau einer Komponente.
\begin{minted}{ts}
@Component({
selector: '...',
standalone: true,
imports: [...],
templateUrl: '...',
styleUrls: ['..']
})
export class NameDerKomponente {
...
}
\end{minted}
In @Component wird zunächst im Attribut selector ein Selektor angegeben, der die Elemente im DOM auswählt, an die die Komponente gebunden werden soll.
Dabei handelt es sich um einen Namen der Komponente, der an anderer Stelle als Tag verwendet werden kann.
An der Stelle, an der dieser Selektor angegeben wird, wird zur Laufzeit der View der Komponente eingefügt.
Das auf den Selektor matchende Element wird dabei als Host- Element bezeichnet.
Wird als selector nur ein Elementname angegeben, wird ein entsprechendes HTML-Tag gesucht und dessen Inhalt durch den View der Komponente ersetzt.
In der eigentlichen Klasse der Komponente wird das Datenmodell und die Businesslogik der Komponente erstellt.
\item Worum handelt es sich bei Lifecycle-Hooks?
Methoden, die, falls sie vom Entwickler definiert wurden, automatisch aufgerufen werden (Callback-Methoden). Sobald eine Komponente den Zustand wechselt, wird die entsprechende Lifecycle-Hook-Methode aufgerufen.
\item Welchen Zweck erfüllt das Angular-CLI?
Das CLI umfasst eine Reihe von Befehlen für sich wiederholende Tätigkeiten, so dass Entwicklern die manuelle Erstellung dieser Dateien abgenommen wird. Mit dem CLI können die Bestandteile der Angular-Anwendung, wie beispielsweise Komponenten oder Klassen, bis hin zum ganzen Angular-Projekt erstellt werden, und stellt somit das Standardvorgehen zum Erstellen
projektrelevanter Dateien dar.
\item Worum handelt es sich bei der Interpolation?
Bei der Interpolation können Daten aus der Komponentenklasse im Template angezeigt werden.
z.B:
Komponent:
\begin{minted}{ts}
export class AppComponent {
location: string;
constructor(){ this.location = 'Welt'; }
}
\end{minted}
Template:
\begin{minted}{ng2}
Hallo {{ location }}!
\end{minted}
\item Wie kann durch ein Property Binding ein Attribut einer Kind-Komponente gesetzt werden? Geben Sie ein Beispiel hierfür an.
Im Template der Root-Komponente:
\begin{minted}{ng2}
<kind-komponente [Eigenschaft der Kind-Komponente]="Eigenschaft der Eltern-Komponente">
..
</kind-komponente>
\end{minted}
\item Wie wird ein Event-Binding mit einem JavaScript-Event erstellt? Geben Sie ein Beispiel mit einem Knopf und dem click-Event an.
Template:
\begin{minted}{ng2}
<button (click)="verarbeiteKlick()">Klick</button>
Anzahl der Klicks: {{ klickZaehler }}
\end{minted}
Komponent:
\begin{minted}{ts}
export class EventComponent implements OnInit {
klickZaehler!: number;
ngOnInit() { this.klickZaehler = 0; }
verarbeiteKlick() {
this.klickZaehler++;
}
}
\end{minted}
\item Beschreiben Sie das Vorgehen, um ein selbstdefiniertes Event in der Kind-Komponente zu erstellen und in der Eltern-Komponente zu empfangen.
In der Kind-Komponente muss zunächst das event erstellt werden:
\begin{minted}{ts}
@Output() event = new EventEmitter();
\end{minted}
Dieses kann dann in der Eltern-Komponente verwendet verwenden:
\begin{minted}{ng2}
<tag (event)="funktionsname()">...
\end{minted}
Das event kann wie folgt aktiviert werden, damit die Eltern-Komponente dann auch das Event bekommt:
\begin{minted}{ts}
this.event.emit();
\end{minted}
\item Erklären Sie die Verwendung der Strukturdirektive *ngIf.
Die Strukturdirektive *ngIf wird verwendet, um ein DOM Element nur unter einer Bedingung einzufügen.
\item Beschreiben Sie, wie die Strukturdirektive *ngFor verwendet werden kann.
Die Strukturdirektive *ngFor wird verwendet, um ein DOM Element bei der Instanziierung des Templates mehrfach einzufügen.
\item Erstellen Sie eine TypeScript Klasse namens Auto mit den Attributen Hersteller, Typ und Kennzeichen vom Typ string.
\begin{minted}{ts}
class Auto {
constructor(
private _hersteller: string,
private _typ: string,
private _kennzeichen: string,
) {
}
get typ(): string { return this._typ; }
set typ(typ: string) { this._typ = typ; }
get hersteller(): string { return this._hersteller; }
set hersteller(hersteller: string) { this._hersteller = hersteller; }
get kennzeichen(): string { return this._kennzeichen; }
set kennzeichen(kennzeichen: string) { this._kennzeichen = kennzeichen; }
}
\end{minted}
\item Erstellen Sie ein Programm in dem im Template einer Komponente ein Knopf erstellt wird, der beim click-Event eine Methode aufruft. In dieser Methode soll ein Objekt vom Typ Auto (siehe vorherige Aufgabe) erstellt werden. Dieses Objekt soll anschließend per Event-Binding an eine Eltern-Komponente gesendet und dort in einem Attribut gespeichert werden. Abschließend geben Sie die Attribute des empfangenen Auto-Objekts im Template der Eltern-Komponente aus. Bei der Ausgabe soll beachtet werden, dass es zu keinem Fehler kommen darf (siehe Konsole), falls das Event noch nicht empfangen wurde und das Auto-Attribut (noch) undefined ist. \textit{Die Konsole wird in den meisten Browsern über F12 oder CMD-alt-i geöffnet.}
Main page:
\begin{minted}{ts}
export class AppComponent {
title = 'demo';
constructor(public auto?: Auto) {
}
setAuto(auto: Auto) {
this.auto = auto;
}
}
\end{minted}
Main page template:
\begin{minted}{ng2}
<main class="main">
<div class="content">
<create-auto (autoInitializedEvent)="setAuto($event)"/>
<div> Typ: {{ auto?.typ ?? "N/A" }} </div>
<div> Hersteller: {{ auto?.hersteller ?? "N/A" }} </div>
<div> Kennzeichen: {{ auto?.kennzeichen ?? "N/A" }} </div>
</div>
</main>
\end{minted}
Auto erstellen kompolnente:
\begin{minted}{ts}
export class CreateAutoComponent {
constructor(
@Output() public autoInitializedEvent: EventEmitter<Auto>
) {
autoInitializedEvent = new EventEmitter<Auto>();
}
createAuto() {
var auto = new Auto("BMW", "e36", "DE-gho-st");
this.autoInitializedEvent.emit(auto);
}
}
\end{minted}
Auto erstellen template:
\begin{minted}{ng2}
<button (click)="createAuto">Auto erstellen</button>
\end{minted}
\end{exercises}
\end{document})

View File

@@ -15,6 +15,10 @@
\RequirePackage{graphicx} \RequirePackage{graphicx}
\RequirePackage{amsmath} \RequirePackage{amsmath}
\RequirePackage{hyperref} \RequirePackage{hyperref}
\RequirePackage{minted}
% Minted config
\usemintedstyle{default}
% Define chapter counter for exercise sheets % Define chapter counter for exercise sheets
\newcounter{chapter} \newcounter{chapter}

27
flake.lock generated
View File

@@ -5,11 +5,11 @@
"nixpkgs-lib": "nixpkgs-lib" "nixpkgs-lib": "nixpkgs-lib"
}, },
"locked": { "locked": {
"lastModified": 1762980239, "lastModified": 1763759067,
"narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=", "narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=",
"owner": "hercules-ci", "owner": "hercules-ci",
"repo": "flake-parts", "repo": "flake-parts",
"rev": "52a2caecc898d0b46b2b905f058ccc5081f842da", "rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -29,8 +29,24 @@
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4",
"type": "github"
}
},
"nixpkgs-angular-cli": {
"locked": {
"lastModified": 1764947035,
"narHash": "sha256-EYHSjVM4Ox4lvCXUMiKKs2vETUSL5mx+J2FfutM7T9w=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a672be65651c80d3f592a89b3945466584a22069",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a672be65651c80d3f592a89b3945466584a22069",
"type": "github" "type": "github"
} }
}, },
@@ -52,7 +68,8 @@
"root": { "root": {
"inputs": { "inputs": {
"flake-parts": "flake-parts", "flake-parts": "flake-parts",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs",
"nixpkgs-angular-cli": "nixpkgs-angular-cli"
} }
} }
}, },

View File

@@ -3,10 +3,15 @@
inputs = { inputs = {
flake-parts.url = "github:hercules-ci/flake-parts"; flake-parts.url = "github:hercules-ci/flake-parts";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4";
nixpkgs-angular-cli.url = "github:NixOS/nixpkgs/a672be65651c80d3f592a89b3945466584a22069";
}; };
outputs = inputs @ {flake-parts, ...}: outputs = inputs @ {
flake-parts,
self,
...
}:
flake-parts.lib.mkFlake {inherit inputs;} { flake-parts.lib.mkFlake {inherit inputs;} {
imports = []; imports = [];
systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"]; systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"];
@@ -45,6 +50,14 @@
upquote upquote
])) ]))
]; ];
pkgs-angular-cli = import inputs.nixpkgs-angular-cli {
inherit system;
};
angularPackages = with pkgs-angular-cli; [
nodejs_25
];
in { in {
# Per-system attributes can be defined here. The self' and inputs' # Per-system attributes can be defined here. The self' and inputs'
# module parameters provide easy access to attributes of the same # module parameters provide easy access to attributes of the same
@@ -79,12 +92,13 @@
mkdir -p $out/share $out/log $out/artifacts mkdir -p $out/share $out/log $out/artifacts
cp out/uebung-${toString n}.pdf "$out/share/${name}" cp out/uebung-${toString n}.pdf "$out/share/${name}"
cp out/*.log $out/log/ cp out/*.log $out/log/
cp out/* $out/artifacts cp -r out/* $out/artifacts
''; '';
} }
// args; // args;
in { in {
"uebung-5" = mkUebungPdf 5 {}; "uebung-5" = mkUebungPdf 5 {};
"uebung-6" = mkUebungPdf 6 {};
}; };
devShells.default = with pkgs; devShells.default = with pkgs;
@@ -95,13 +109,40 @@
mermaid-cli mermaid-cli
openjdk openjdk
jetty jetty
ant maven
] ]
++ latexPackages; ++ latexPackages
++ angularPackages;
shellHook =
# bash
''
# jetty docs: https://jetty.org/docs/jetty/12.1/operations-guide/begin/index.html
export JETTY_HOME="$(readlink -f .)/.jetty/home"
export JETTY_BASE="$(readlink -f .)/.jetty/base"
mkdir -p "$JETTY_HOME" "$JETTY_BASE"
for item in ${pkgs.jetty}/*; do
ln -sf "$item" "$JETTY_HOME/"
done
jetty() {
mkdir -p $JETTY_BASE/webapps/
ln -fs "$(readlink -f target/*.war)" $JETTY_BASE/webapps/
java \
-Djetty.home="$JETTY_HOME" \
-Djetty.base="$JETTY_BASE" \
-jar $JETTY_HOME/start.jar $@
}
jetty --add-modules=http,ee11-cdi,ee11-ext,ee11-deploy,ee11-environment,ee11-annotations,ee11-glassfish-jstl,ee11-jndi,ee11-jsp,ee11-jstl,ee11-plus,ee11-security,ee11-servlet,ee11-servlets,ee11-webapp,ee11-websocket-jakarta,ee11-websocket-jetty,ee11-websocket-jetty-client-webapp
shellHook = ''
echo "Usage Example:" echo "Usage Example:"
echo "jetty ..." echo "mvn clean package # build demo.war"
echo "jetty # run webserver"
alias ng="npx ng"
''; '';
}; };
}; };

4037
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

6
package.json Normal file
View File

@@ -0,0 +1,6 @@
{
"dependencies": {
"@angular/cli": "^21.0.2",
"@angular/core": "^21.0.3"
}
}

61
pom.xml
View File

@@ -1,59 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId> <groupId>org.example</groupId>
<artifactId>demo</artifactId> <artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version> <version>1.0-SNAPSHOT</version>
<name>demo</name> <name>demo</name>
<packaging>war</packaging> <packaging>war</packaging>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>8</maven.compiler.target> <project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.release>21</maven.compiler.release>
<junit.version>5.11.0-M2</junit.version> <junit.version>5.11.0-M2</junit.version>
<compiler-plugin.version>3.13.0</compiler-plugin.version>
<war-plugin.version>3.4.0</war-plugin.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>jakarta.platform</groupId> <groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId> <artifactId>jakarta.jakartaee-web-api</artifactId>
<version>11.0.0-M3</version> <version>11.0.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency><dependency> </dependency>
<groupId>org.jboss.weld.se</groupId> <dependency>
<artifactId>weld-se-core</artifactId> <groupId>org.glassfish</groupId>
<version>6.0.0.Beta1</version> <artifactId>jakarta.faces</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-el-api</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.jboss.weld.servlet</groupId>
<artifactId>weld-servlet-core</artifactId>
<version>5.1.2.Final</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version> <version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>RELEASE</version> <version>1.18.30</version>
<scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<finalName>demo</finalName>
<plugins> <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version> <version>${war-plugin.version}</version>
</plugin> </plugins> </plugin>
</plugins>
</build> </build>
</project> </project>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/beans_4_0.xsd"
version="4.0" bean-discovery-mode="annotated">
</beans>

View File

@@ -3,11 +3,18 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0"> version="6.0">
<context-param>
<param-name>jakarta.faces.CONFIG_FILES</param-name>
<param-value>/WEB-INF/faces-config.xml</param-value>
</context-param>
<servlet> <servlet>
<servlet-name>Faces Servlet</servlet-name> <servlet-name>Faces Servlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class> <servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup> <load-on-startup>1</load-on-startup>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>Faces Servlet</servlet-name> <servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern> <url-pattern>*.xhtml</url-pattern>