Compare commits
18 Commits
d334c43fe4
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| e30023b90c | |||
| 60393acf34 | |||
| 71ae42c3a2 | |||
| cee92030ad | |||
| 0d33fa55a7 | |||
| 590b6e86e4 | |||
| 37b17c4f95 | |||
| 89e8e7371c | |||
| 00a33b4cd2 | |||
| 4c63b5927d | |||
| 3b983ebbf4 | |||
| 314a581378 | |||
| f317ae2f4d | |||
| af5da29daf | |||
| a8a8ec9779 | |||
| 210dd12663 | |||
| 761eb6f4a6 | |||
| b98cbf3615 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -40,3 +40,10 @@ build/
|
||||
### nix / direnv
|
||||
.direnv
|
||||
result
|
||||
|
||||
### jetty
|
||||
**/.jetty/home
|
||||
**/.jetty/base
|
||||
|
||||
### Angualr Demo ###
|
||||
**/node_modules
|
||||
|
||||
BIN
bin/Kapitel7_Angular_Teil2_Praktikum.war
Normal file
BIN
bin/Kapitel7_Angular_Teil2_Praktikum.war
Normal file
Binary file not shown.
17
demo/.editorconfig
Normal file
17
demo/.editorconfig
Normal 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
43
demo/.gitignore
vendored
Normal 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
59
demo/README.md
Normal 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
73
demo/angular.json
Normal 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
9338
demo/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
43
demo/package.json
Normal file
43
demo/package.json
Normal 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
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
18
demo/src/app/Auto.ts
Normal 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; }
|
||||
}
|
||||
13
demo/src/app/Student.ts
Normal file
13
demo/src/app/Student.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export class Student {
|
||||
constructor(
|
||||
private _name?: string,
|
||||
private _matrikelnummer?: number,
|
||||
) {
|
||||
}
|
||||
|
||||
get name(): string|undefined { return this._name; }
|
||||
set name(name: string) { this._name = name; }
|
||||
|
||||
get matrikelnummer(): number|undefined { return this._matrikelnummer; }
|
||||
set matrikelnummer(matrikelnummer: number) { this._matrikelnummer = matrikelnummer; }
|
||||
}
|
||||
11
demo/src/app/app.config.ts
Normal file
11
demo/src/app/app.config.ts
Normal 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
210
demo/src/app/app.html
Normal 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 />
|
||||
8
demo/src/app/app.routes.ts
Normal file
8
demo/src/app/app.routes.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { Routes } from '@angular/router';
|
||||
import { StudentForm } from './student-form/student-form';
|
||||
import { StudentFormReactive } from './student-form-reactive/student-form-reactive';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: 'student', component: StudentForm },
|
||||
{ path: 'student-reactive', component: StudentFormReactive }
|
||||
];
|
||||
23
demo/src/app/app.spec.ts
Normal file
23
demo/src/app/app.spec.ts
Normal 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');
|
||||
});
|
||||
});
|
||||
21
demo/src/app/app.ts
Normal file
21
demo/src/app/app.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
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';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet, CreateAutoComponent, DisplayHtmlComponent, FormsModule],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.css'
|
||||
})
|
||||
export class App {
|
||||
protected readonly title = signal('demo');
|
||||
auto?: Auto;
|
||||
|
||||
setAuto(auto: Auto) {
|
||||
this.auto = auto;
|
||||
}
|
||||
}
|
||||
0
demo/src/app/create-auto/create-auto.css
Normal file
0
demo/src/app/create-auto/create-auto.css
Normal file
1
demo/src/app/create-auto/create-auto.html
Normal file
1
demo/src/app/create-auto/create-auto.html
Normal file
@@ -0,0 +1 @@
|
||||
<button (click)="createAuto()">Auto erstellen</button>
|
||||
23
demo/src/app/create-auto/create-auto.spec.ts
Normal file
23
demo/src/app/create-auto/create-auto.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
17
demo/src/app/create-auto/create-auto.ts
Normal file
17
demo/src/app/create-auto/create-auto.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
0
demo/src/app/display-html/display-html.css
Normal file
0
demo/src/app/display-html/display-html.css
Normal file
4
demo/src/app/display-html/display-html.html
Normal file
4
demo/src/app/display-html/display-html.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<div>
|
||||
<p innerHtml="{{ html }}"></p>
|
||||
<button (click)="updateHtml()">Update Html</button>
|
||||
</div>
|
||||
23
demo/src/app/display-html/display-html.spec.ts
Normal file
23
demo/src/app/display-html/display-html.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
15
demo/src/app/display-html/display-html.ts
Normal file
15
demo/src/app/display-html/display-html.ts
Normal 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>";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
input.ng-invalid {
|
||||
background-color: tomato;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<p>Student: </p>
|
||||
<form [formGroup]="form">
|
||||
<label for="name">Name: </label>
|
||||
<input type="text" id="name" formControlName="name"/>
|
||||
<label for="matrikelnummer">Matrikelnummer: </label>
|
||||
<input type="number" id="matrikelnummer" formControlName="matrikelnummer"/>
|
||||
<button type="submit" (click)="print()">Ausgeben</button>
|
||||
</form>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StudentFormReactive } from './student-form-reactive';
|
||||
|
||||
describe('StudentFormReactive', () => {
|
||||
let component: StudentFormReactive;
|
||||
let fixture: ComponentFixture<StudentFormReactive>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [StudentFormReactive]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(StudentFormReactive);
|
||||
component = fixture.componentInstance;
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
26
demo/src/app/student-form-reactive/student-form-reactive.ts
Normal file
26
demo/src/app/student-form-reactive/student-form-reactive.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Student } from '../Student';
|
||||
|
||||
@Component({
|
||||
selector: 'app-student-form-reactive',
|
||||
imports: [ReactiveFormsModule],
|
||||
templateUrl: './student-form-reactive.html',
|
||||
styleUrl: './student-form-reactive.css',
|
||||
})
|
||||
export class StudentFormReactive {
|
||||
form: FormGroup = null!;
|
||||
|
||||
ngOnInit() {
|
||||
this.form = new FormGroup({
|
||||
name: new FormControl<string|null>(null),
|
||||
matrikelnummer: new FormControl<number|null>(null, [Validators.required, Validators.pattern('\\d+')])
|
||||
});
|
||||
}
|
||||
|
||||
print() {
|
||||
const value = this.form.value;
|
||||
const model = new Student(value.name, value.matrikelnummer);
|
||||
console.log(model);
|
||||
}
|
||||
}
|
||||
5
demo/src/app/student-form/student-form.css
Normal file
5
demo/src/app/student-form/student-form.css
Normal file
@@ -0,0 +1,5 @@
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
}
|
||||
8
demo/src/app/student-form/student-form.html
Normal file
8
demo/src/app/student-form/student-form.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<p>Student: </p>
|
||||
<form #formularName="ngForm">
|
||||
<label for="name">Name: </label>
|
||||
<input type="text" name="name" [(ngModel)]="model.name"/>
|
||||
<label for="matrikelnummer">Matrikelnummer: </label>
|
||||
<input type="number" name="matrikelnummer" [(ngModel)]="model.matrikelnummer"/>
|
||||
<button type="submit" (click)="print()">Ausgeben</button>
|
||||
</form>
|
||||
23
demo/src/app/student-form/student-form.spec.ts
Normal file
23
demo/src/app/student-form/student-form.spec.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { StudentForm } from './student-form';
|
||||
|
||||
describe('StudentForm', () => {
|
||||
let component: StudentForm;
|
||||
let fixture: ComponentFixture<StudentForm>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [StudentForm]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(StudentForm);
|
||||
component = fixture.componentInstance;
|
||||
await fixture.whenStable();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
17
demo/src/app/student-form/student-form.ts
Normal file
17
demo/src/app/student-form/student-form.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Student } from '../Student';
|
||||
|
||||
@Component({
|
||||
selector: 'app-student-form',
|
||||
imports: [ FormsModule],
|
||||
templateUrl: './student-form.html',
|
||||
styleUrl: './student-form.css',
|
||||
})
|
||||
export class StudentForm {
|
||||
model: Student = new Student();
|
||||
|
||||
print() {
|
||||
console.log(this.model)
|
||||
}
|
||||
}
|
||||
13
demo/src/index.html
Normal file
13
demo/src/index.html
Normal 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
6
demo/src/main.ts
Normal 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
1
demo/src/styles.css
Normal 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
15
demo/tsconfig.app.json
Normal 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
33
demo/tsconfig.json
Normal 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
15
demo/tsconfig.spec.json
Normal 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"
|
||||
]
|
||||
}
|
||||
@@ -8,13 +8,64 @@
|
||||
\maketitle
|
||||
|
||||
\begin{exercises}
|
||||
\item Worum handelt es sich bei Facelets und welche Vorteile bietet die Verwendung von Facelets?
|
||||
\item Wie können Templates mit Facelets erstellt bzw. verwendet werden?
|
||||
\item Worum handelt es sich bei PrimeFaces?
|
||||
\item Welcher Namespace wird für die Verwendung von PrimeFaces benutzt?
|
||||
\item Wie kann per Ajax auf die Eingabe eines Tastenklicks reagiert werden?
|
||||
\item Zählen Sie vier PrimeFaces-Komponenten auf und geben deren Funktion an.
|
||||
\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 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?
|
||||
|
||||
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?
|
||||
|
||||
PrimeFaces stellen eine Komponentenbibliothek dar, die Komponenten mit AJAX-Unterstützung anbieten.
|
||||
|
||||
\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?
|
||||
|
||||
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.
|
||||
|
||||
\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).
|
||||
|
||||
\end{exercises}
|
||||
|
||||
\end{document}
|
||||
|
||||
248
docs/uebungen/uebung-6.tex
Normal file
248
docs/uebungen/uebung-6.tex
Normal file
@@ -0,0 +1,248 @@
|
||||
\documentclass{uebung}
|
||||
|
||||
\author{Linus Nagel}
|
||||
\chapter{6}
|
||||
|
||||
\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})
|
||||
208
docs/uebungen/uebung-7.tex
Normal file
208
docs/uebungen/uebung-7.tex
Normal file
@@ -0,0 +1,208 @@
|
||||
\documentclass{uebung}
|
||||
|
||||
\author{Linus Nagel}
|
||||
\chapter{7}
|
||||
|
||||
\begin{document}
|
||||
|
||||
\maketitle
|
||||
|
||||
\begin{exercises}
|
||||
\item Erläutern Sie, wie das Routing von Angular grundsätzlich funktioniert.
|
||||
|
||||
\begin{itemize}
|
||||
\item Durch Routing werden an einer definierten Stelle der Webseite (dem router-outlet), die Templates von ausgewählten Komponenten dargestellt.
|
||||
\item Die Auswahl der anzuzeigenden Komponente erfolgt dabei abhängig von der eingegebenen URL.
|
||||
\end{itemize}
|
||||
|
||||
Routen werden (z.B. mit modulebasierten Komponenten) in app-routing.module.ts definiert:
|
||||
\begin{minted}[breaklines]{ts}
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
const routes: Routes = [
|
||||
{path: '', component: component1}, // Root-URL
|
||||
{path: 'URL1', component: component1},
|
||||
{path: 'URL2', component: component2}
|
||||
];
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
||||
\end{minted}
|
||||
|
||||
Mit RouterOutlet kann wird dann gesagt, wo die Komponenten der Routen ausgegeben werden:
|
||||
\begin{minted}[breaklines]{ng2}
|
||||
<router-outlet></router-outlet>
|
||||
\end{minted}
|
||||
|
||||
Anstatt normalen anchor Elementen müssen dann auch RouterLinks verwendet werden, damit kein echter redirekt passiert, sondern Angular nur die Komponenten nachläd:
|
||||
\begin{minted}[breaklines]{ng2}
|
||||
<a routerLink="/Pfad">...</a>
|
||||
\end{minted}
|
||||
|
||||
\item Wie kann eine Route mit einem Parameter erstellt und ausgelesen werden?
|
||||
|
||||
Routen mit Parametern werden wie folgt deklariert:
|
||||
\begin{minted}[breaklines]{ts}
|
||||
{path: 'URL/:NameDesParameters', component: Komponentenbezeichner}
|
||||
\end{minted}
|
||||
|
||||
Geschrieben werden die Parameter in den RouterLinks so:
|
||||
\begin{minted}[breaklines]{ng2}
|
||||
<a routerLink="/URL/ParameterWert">...</a>
|
||||
<a [routerLink]="['/URL', ParameterWert]">...</a>
|
||||
\end{minted}
|
||||
|
||||
Ausgelesen werden die Parameter in den Komponenten zu denen die Route führt (mit Dependency Injection):
|
||||
\begin{minted}[breaklines]{ts}
|
||||
constructor(private routeObject: ActivatedRoute) {
|
||||
const parameter = this.routeObject.snapshot.params['NameDesParameters'];
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
\item Erklären Sie, wie die Werte eines Observables empfangen werden können.
|
||||
|
||||
Man übergibt der subscribe Methode eine Funktion, die aufgerufen wird, wenn Daten empfagen werden:
|
||||
\begin{minted}[breaklines]{ts}
|
||||
const data: Observable<string> = this.sendeDaten();
|
||||
const subscription = data.subscribe(value => console.log(value));
|
||||
\end{minted}
|
||||
|
||||
\item Wie kann der Empfang von Observables beendet werden?
|
||||
|
||||
Mit der unsubscribe Methode:
|
||||
\begin{minted}[breaklines]{ts}
|
||||
const subscription = ...;
|
||||
subscription.unsubscribe();
|
||||
\end{minted}
|
||||
|
||||
\item Beschreiben Sie den Ablauf beim Speichern eines Objekts auf einem Server mittels des HttpModule.
|
||||
|
||||
\begin{enumerate}
|
||||
\item In der Komponente den HttpClient per Dependency Injection erhalten
|
||||
\item auf dem httpClient object die \texttt{post} Methode aufrufen
|
||||
\item Optional noch auf dem Observable, das man von der post Methode erhält subscriben, und die Response verarbeiten.
|
||||
\end{enumerate}
|
||||
|
||||
\item Erstellen Sie eine Klasse Student mit den Attributen name (string) und matrikelnummer (number). Erstellen Sie zudem mittels Template Driven Forms ein Formular sowie die zugehörige Komponentenklasse, so dass alle Daten vom Typ Student eingegeben werden können. Die Formularfelder sollen dabei mit einem Objekt vom Typ Student in der Komponentenklasse bidirektional verknüpft sein. Unter dem Formular soll sich ein Knopf befinden, der, sobald er geklickt wird, eine Methode aufruft, die den (ggf. geänderten) Inhalt des Studentenobjekts in der Konsole ausgibt.
|
||||
|
||||
Student.ts:
|
||||
\begin{minted}[breaklines]{ts}
|
||||
export class Student {
|
||||
constructor(
|
||||
private _name?: string,
|
||||
private _matrikelnummer?: number,
|
||||
) {
|
||||
}
|
||||
|
||||
get name(): string|undefined { return this._name; }
|
||||
set name(name: string) { this._name = name; }
|
||||
|
||||
get matrikelnummer(): number|undefined { return this._matrikelnummer; }
|
||||
set matrikelnummer(matrikelnummer: number) { this._matrikelnummer = matrikelnummer; }
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
student-form.ts
|
||||
\begin{minted}[breaklines]{ts}
|
||||
import { Component } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Student } from '../Student';
|
||||
|
||||
@Component({
|
||||
selector: 'app-student-form',
|
||||
imports: [ FormsModule],
|
||||
templateUrl: './student-form.html',
|
||||
styleUrl: './student-form.css',
|
||||
})
|
||||
export class StudentForm {
|
||||
model: Student = new Student();
|
||||
|
||||
print() {
|
||||
console.log(this.model)
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
student-form.css
|
||||
\begin{minted}[breaklines]{css}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
student-form.html
|
||||
\begin{minted}[breaklines]{ng2}
|
||||
<p>Student: </p>
|
||||
<form #formularName="ngForm">
|
||||
<label for="name">Name: </label>
|
||||
<input type="text" name="name" [(ngModel)]="model.name"/>
|
||||
<label for="matrikelnummer">Matrikelnummer: </label>
|
||||
<input type="number" name="matrikelnummer" [(ngModel)]="model.matrikelnummer"/>
|
||||
<button type="submit" (click)="print()">Ausgeben</button>
|
||||
</form>
|
||||
\end{minted}
|
||||
|
||||
\item Erstellen Sie das gleiche Formular wie in der vorhergehenden Aufgabe, diesmal jedoch mit Reactive Forms. Fügen Sie dem Formular eine Validierung hinzu, die die Matrikelnummer zum Pflichtfeld macht und die prüft, ob als Matrikelnummer ausschließlich Ziffern verwendet wurden. Falls dies nicht der Fall ist, soll das Textfeld einen hellroten Hintergrund erhalten.
|
||||
|
||||
student-form-reactive.ts
|
||||
\begin{minted}[breaklines]{ts}
|
||||
import { Component } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Student } from '../Student';
|
||||
|
||||
@Component({
|
||||
selector: 'app-student-form-reactive',
|
||||
imports: [ReactiveFormsModule],
|
||||
templateUrl: './student-form-reactive.html',
|
||||
styleUrl: './student-form-reactive.css',
|
||||
})
|
||||
export class StudentFormReactive {
|
||||
form: FormGroup = null!;
|
||||
|
||||
ngOnInit() {
|
||||
this.form = new FormGroup({
|
||||
name: new FormControl<string|null>(null),
|
||||
matrikelnummer: new FormControl<number|null>(null, [Validators.required, Validators.pattern('\\d+')])
|
||||
});
|
||||
}
|
||||
|
||||
print() {
|
||||
const value = this.form.value;
|
||||
const model = new Student(value.name, value.matrikelnummer);
|
||||
console.log(model);
|
||||
}
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
student-form-reactive.css
|
||||
\begin{minted}[breaklines]{css}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
input.ng-invalid {
|
||||
background-color: tomato;
|
||||
}
|
||||
\end{minted}
|
||||
|
||||
student-form-reactive.html
|
||||
\begin{minted}[breaklines]{ng2}
|
||||
<p>Student: </p>
|
||||
<form [formGroup]="form">
|
||||
<label for="name">Name: </label>
|
||||
<input type="text" id="name" formControlName="name"/>
|
||||
<label for="matrikelnummer">Matrikelnummer: </label>
|
||||
<input type="number" id="matrikelnummer" formControlName="matrikelnummer"/>
|
||||
<button type="submit" (click)="print()">Ausgeben</button>
|
||||
</form>
|
||||
\end{minted}
|
||||
|
||||
\end{exercises}
|
||||
|
||||
\end{document}
|
||||
@@ -15,6 +15,10 @@
|
||||
\RequirePackage{graphicx}
|
||||
\RequirePackage{amsmath}
|
||||
\RequirePackage{hyperref}
|
||||
\RequirePackage{minted}
|
||||
|
||||
% Minted config
|
||||
\usemintedstyle{default}
|
||||
|
||||
% Define chapter counter for exercise sheets
|
||||
\newcounter{chapter}
|
||||
|
||||
27
flake.lock
generated
27
flake.lock
generated
@@ -5,11 +5,11 @@
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1762980239,
|
||||
"narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=",
|
||||
"lastModified": 1763759067,
|
||||
"narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "52a2caecc898d0b46b2b905f058ccc5081f842da",
|
||||
"rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -29,8 +29,24 @@
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
@@ -52,7 +68,8 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-angular-cli": "nixpkgs-angular-cli"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
63
flake.nix
63
flake.nix
@@ -3,10 +3,15 @@
|
||||
|
||||
inputs = {
|
||||
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;} {
|
||||
imports = [];
|
||||
systems = ["x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin"];
|
||||
@@ -45,6 +50,14 @@
|
||||
upquote
|
||||
]))
|
||||
];
|
||||
|
||||
pkgs-angular-cli = import inputs.nixpkgs-angular-cli {
|
||||
inherit system;
|
||||
};
|
||||
|
||||
angularPackages = with pkgs-angular-cli; [
|
||||
nodejs_25
|
||||
];
|
||||
in {
|
||||
# Per-system attributes can be defined here. The self' and inputs'
|
||||
# module parameters provide easy access to attributes of the same
|
||||
@@ -79,12 +92,14 @@
|
||||
mkdir -p $out/share $out/log $out/artifacts
|
||||
cp out/uebung-${toString n}.pdf "$out/share/${name}"
|
||||
cp out/*.log $out/log/
|
||||
cp out/* $out/artifacts
|
||||
cp -r out/* $out/artifacts
|
||||
'';
|
||||
}
|
||||
// args;
|
||||
in {
|
||||
"uebung-5" = mkUebungPdf 5 {};
|
||||
"uebung-6" = mkUebungPdf 6 {};
|
||||
"uebung-7" = mkUebungPdf 7 {};
|
||||
};
|
||||
|
||||
devShells.default = with pkgs;
|
||||
@@ -95,14 +110,44 @@
|
||||
mermaid-cli
|
||||
openjdk
|
||||
jetty
|
||||
ant
|
||||
maven
|
||||
]
|
||||
++ latexPackages;
|
||||
++ latexPackages
|
||||
++ angularPackages;
|
||||
|
||||
shellHook = ''
|
||||
echo "Usage Example:"
|
||||
echo "jetty ..."
|
||||
'';
|
||||
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
|
||||
|
||||
mkdir -p $JETTY_BASE/webapps/
|
||||
|
||||
deploy() {
|
||||
ln -fs "$(realpath $1)" $JETTY_BASE/webapps/
|
||||
}
|
||||
|
||||
jetty() {
|
||||
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
|
||||
|
||||
echo "Usage Example:"
|
||||
echo "mvn clean package # build demo.war"
|
||||
echo "jetty # run webserver"
|
||||
|
||||
alias ng="npx ng"
|
||||
'';
|
||||
};
|
||||
};
|
||||
flake = {
|
||||
|
||||
4037
package-lock.json
generated
Normal file
4037
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
6
package.json
Normal file
6
package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@angular/cli": "^21.0.2",
|
||||
"@angular/core": "^21.0.3"
|
||||
}
|
||||
}
|
||||
75
pom.xml
75
pom.xml
@@ -1,59 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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">
|
||||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>demo</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<name>demo</name>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<project.report.sourceEncoding>UTF-8</project.report.sourceEncoding>
|
||||
<maven.compiler.release>21</maven.compiler.release>
|
||||
<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>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.platform</groupId>
|
||||
<artifactId>jakarta.jakartaee-web-api</artifactId>
|
||||
<version>11.0.0-M3</version>
|
||||
<version>11.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency><dependency>
|
||||
<groupId>org.jboss.weld.se</groupId>
|
||||
<artifactId>weld-se-core</artifactId>
|
||||
<version>6.0.0.Beta1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<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>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<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>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>RELEASE</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.30</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>demo</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${compiler-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
</plugin> </plugins>
|
||||
<version>${war-plugin.version}</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
6
src/main/webapp/WEB-INF/beans.xml
Normal file
6
src/main/webapp/WEB-INF/beans.xml
Normal 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>
|
||||
@@ -3,11 +3,18 @@
|
||||
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"
|
||||
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-name>Faces Servlet</servlet-name>
|
||||
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>Faces Servlet</servlet-name>
|
||||
<url-pattern>*.xhtml</url-pattern>
|
||||
|
||||
Reference in New Issue
Block a user