This commit is contained in:
2025-12-06 08:46:55 +01:00
parent a8a8ec9779
commit af5da29daf
30 changed files with 15869 additions and 3 deletions

7
.gitignore vendored
View File

@@ -42,5 +42,8 @@ build/
result result
### jetty ### jetty
.jetty/home **/.jetty/home
.jetty/base **/.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

42
demo/.gitignore vendored Normal file
View File

@@ -0,0 +1,42 @@
# 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
# System files
.DS_Store
Thumbs.db

101
demo/angular.json Normal file
View File

@@ -0,0 +1,101 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"demo": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/demo",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.css"
],
"scripts": [],
"server": "src/main.server.ts",
"prerender": true,
"ssr": {
"entry": "src/server.ts"
}
},
"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-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "demo:build:production"
},
"development": {
"buildTarget": "demo:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json",
"assets": [
{
"glob": "**/*",
"input": "public"
}
],
"styles": [
"src/styles.css"
],
"scripts": []
}
}
}
}
}
}

14917
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",
"serve:ssr:demo": "node dist/demo/server/server.mjs"
},
"private": true,
"dependencies": {
"@angular/common": "^19.2.0",
"@angular/compiler": "^19.2.0",
"@angular/core": "^19.2.0",
"@angular/forms": "^19.2.0",
"@angular/platform-browser": "^19.2.0",
"@angular/platform-browser-dynamic": "^19.2.0",
"@angular/platform-server": "^19.2.0",
"@angular/router": "^19.2.0",
"@angular/ssr": "^19.2.3",
"express": "^4.18.2",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.2.3",
"@angular/cli": "^19.2.3",
"@angular/compiler-cli": "^19.2.0",
"@types/express": "^4.17.17",
"@types/jasmine": "~5.1.0",
"@types/node": "^18.18.0",
"jasmine-core": "~5.6.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.7.2"
}
}

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

View File

@@ -0,0 +1,197 @@
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * 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;
}
.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(--french-violet);
}
.pill-group .pill:nth-child(6n + 3),
.pill-group .pill:nth-child(6n + 4),
.pill-group .pill:nth-child(6n + 5) {
--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">
<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>
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content above * * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<router-outlet />

View File

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

View File

@@ -0,0 +1,21 @@
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Auto } from './Auto';
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {
title = 'demo';
constructor(public auto?: Auto) {
}
setAuto(auto: Auto) {
this.auto = auto;
}
}

View File

@@ -0,0 +1,11 @@
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { appConfig } from './app.config';
const serverConfig: ApplicationConfig = {
providers: [
provideServerRendering(),
]
};
export const config = mergeApplicationConfig(appConfig, serverConfig);

View File

@@ -0,0 +1,9 @@
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { routes } from './app.routes';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes), provideClientHydration(withEventReplay())]
};

View File

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

View File

@@ -0,0 +1,3 @@
<p>create-auto works!</p>
<button (click)="createAuto">Auto erstellen</button>

View File

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

View File

@@ -0,0 +1,21 @@
import { Component, Output, EventEmitter } from '@angular/core';
import { Auto } from '../Auto';
@Component({
selector: 'app-create-auto',
imports: [],
templateUrl: './create-auto.component.html',
styleUrl: './create-auto.component.css'
})
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);
}
}

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>

7
demo/src/main.server.ts Normal file
View File

@@ -0,0 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
export default bootstrap;

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 { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent, appConfig)
.catch((err) => console.error(err));

67
demo/src/server.ts Normal file
View File

@@ -0,0 +1,67 @@
import { APP_BASE_HREF } from '@angular/common';
import { CommonEngine, isMainModule } from '@angular/ssr/node';
import express from 'express';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import bootstrap from './main.server';
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const indexHtml = join(serverDistFolder, 'index.server.html');
const app = express();
const commonEngine = new CommonEngine();
/**
* Example Express Rest API endpoints can be defined here.
* Uncomment and define endpoints as necessary.
*
* Example:
* ```ts
* app.get('/api/**', (req, res) => {
* // Handle API request
* });
* ```
*/
/**
* Serve static files from /browser
*/
app.get(
'**',
express.static(browserDistFolder, {
maxAge: '1y',
index: 'index.html'
}),
);
/**
* Handle all other requests by rendering the Angular application.
*/
app.get('**', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;
commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then((html) => res.send(html))
.catch((err) => next(err));
});
/**
* Start the server if this module is the main entry point.
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
*/
if (isMainModule(import.meta.url)) {
const port = process.env['PORT'] || 4000;
app.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
export default app;

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 */

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

@@ -0,0 +1,19 @@
/* 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": [
"node"
]
},
"files": [
"src/main.ts",
"src/main.server.ts",
"src/server.ts"
],
"include": [
"src/**/*.d.ts"
]
}

27
demo/tsconfig.json Normal file
View File

@@ -0,0 +1,27 @@
/* 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": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"isolatedModules": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"moduleResolution": "bundler",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022"
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

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": [
"jasmine"
]
},
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

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}

View File

@@ -87,12 +87,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;