New Angular based web version #1
@@ -1,13 +1,21 @@
|
||||
<main class="main">
|
||||
<header class="h-12 bg-primary text-primary-contrast">
|
||||
<div class="header max-content-width mx-auto">
|
||||
<div class="header max-content-width mx-auto flex items-center justify-between">
|
||||
<a routerLink="/" class="reset cursor-pointer">
|
||||
Vegasco
|
||||
</a>
|
||||
<span class="flex items-center gap-4">
|
||||
<a routerLink="/entries" class="reset cursor-pointer">
|
||||
Einträge
|
||||
</a>
|
||||
<a routerLink="/cars" class="reset cursor-pointer">
|
||||
Autos
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="content max-content-width mx-auto">
|
||||
<p-toast />
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</main>
|
||||
</main>
|
||||
@@ -9,5 +9,9 @@ export const routes: Routes = [
|
||||
{
|
||||
path: 'entries',
|
||||
loadChildren: () => import('./modules/entries/entries.routes').then(m => m.routes)
|
||||
},
|
||||
{
|
||||
path: 'cars',
|
||||
loadChildren: () => import('./modules/cars/cars.routes').then(m => m.routes)
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { ToastModule } from 'primeng/toast';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
imports: [RouterOutlet, ToastModule],
|
||||
imports: [RouterLink, RouterOutlet, ToastModule],
|
||||
providers: [MessageService],
|
||||
templateUrl: './app.html',
|
||||
styleUrl: './app.scss'
|
||||
|
||||
17
src/Vegasco-Web/src/app/modules/cars/cars.routes.ts
Normal file
17
src/Vegasco-Web/src/app/modules/cars/cars.routes.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Routes } from "@angular/router";
|
||||
import { CarsComponent } from "./cars/cars.component";
|
||||
|
||||
export const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: CarsComponent
|
||||
},
|
||||
{
|
||||
path: 'create',
|
||||
loadComponent: () => import('./edit-car/edit-car.component').then(m => m.EditCarComponent)
|
||||
},
|
||||
{
|
||||
path: 'edit/:id',
|
||||
loadComponent: () => import('./edit-car/edit-car.component').then(m => m.EditCarComponent)
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,38 @@
|
||||
<section>
|
||||
<p-scrollTop />
|
||||
<div class="mb-4 flex gap-2 md:justify-end">
|
||||
<div>
|
||||
<p-button label="Erstellen" routerLink="/cars/create">
|
||||
<ng-icon name="matAddSharp"></ng-icon>
|
||||
</p-button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@if (nonDeletedCars$ | async; as cars) {
|
||||
<p-dataView
|
||||
[value]="cars"
|
||||
[paginator]="true"
|
||||
[rows]="25"
|
||||
[rowsPerPageOptions]="[10, 25, 50, 100]"
|
||||
[pageLinks]="0"
|
||||
[showCurrentPageReport]="true"
|
||||
currentPageReportTemplate="{currentPage} / {totalPages}"
|
||||
layout="list">
|
||||
<ng-template #list let-cars>
|
||||
<div class="flex flex-col gap-2">
|
||||
@for (car of cars; track car.id) {
|
||||
<app-car-card [car]="car"
|
||||
(carDeleted)="onCarDeleted($event)" />
|
||||
}
|
||||
</div>
|
||||
</ng-template>
|
||||
</p-dataView>
|
||||
} @else {
|
||||
<div class="flex flex-col gap-2">
|
||||
@for (_ of skeletonsIterationSource; track $index) {
|
||||
<p-skeleton height="4rem" styleClass="mb-2" />
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,3 @@
|
||||
th, td {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
117
src/Vegasco-Web/src/app/modules/cars/cars/cars.component.ts
Normal file
117
src/Vegasco-Web/src/app/modules/cars/cars/cars.component.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import { AsyncPipe, CommonModule } from '@angular/common';
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, DestroyRef, inject } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormControl, ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouterLink } from '@angular/router';
|
||||
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
||||
import {
|
||||
matAddSharp,
|
||||
} from '@ng-icons/material-icons/sharp';
|
||||
import { CarClient } from '@vegasco-web/api/cars/car-client';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { DataViewModule } from 'primeng/dataview';
|
||||
import { ScrollTopModule } from 'primeng/scrolltop';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { SkeletonModule } from 'primeng/skeleton';
|
||||
import {
|
||||
BehaviorSubject,
|
||||
catchError,
|
||||
combineLatest,
|
||||
EMPTY,
|
||||
map,
|
||||
Observable,
|
||||
throwError
|
||||
} from 'rxjs';
|
||||
import { CarCardComponent } from './components/car-card/car-card.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-entries',
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
ButtonModule,
|
||||
CommonModule,
|
||||
DataViewModule,
|
||||
CarCardComponent,
|
||||
NgIconComponent,
|
||||
ReactiveFormsModule,
|
||||
RouterLink,
|
||||
ScrollTopModule,
|
||||
SelectModule,
|
||||
SkeletonModule,
|
||||
],
|
||||
providers: [
|
||||
provideIcons({
|
||||
matAddSharp,
|
||||
}),
|
||||
],
|
||||
templateUrl: './cars.component.html',
|
||||
styleUrl: './cars.component.scss'
|
||||
})
|
||||
export class CarsComponent {
|
||||
private readonly carClient = inject(CarClient);
|
||||
private readonly messageService = inject(MessageService);
|
||||
|
||||
protected readonly nonDeletedCars$: Observable<Car[]>;
|
||||
|
||||
protected readonly skeletonsIterationSource = Array(10).fill(0);
|
||||
|
||||
private readonly deletedCars$ = new BehaviorSubject(<string[]>[]);
|
||||
|
||||
constructor() {
|
||||
const cars$ = this.carClient.getAll()
|
||||
.pipe(
|
||||
map(response => response.cars),
|
||||
map((cars) => cars
|
||||
.sort((a, b) => a.name.localeCompare(b.name))),
|
||||
);
|
||||
|
||||
this.nonDeletedCars$ = combineLatest([
|
||||
cars$,
|
||||
this.deletedCars$
|
||||
])
|
||||
.pipe(
|
||||
takeUntilDestroyed(),
|
||||
map(([cars, deletedCars]) => cars.filter(car => !deletedCars.includes(car.id))),
|
||||
catchError((error) => this.handleGetCarsError(error)),
|
||||
);
|
||||
}
|
||||
|
||||
onCarDeleted(entry: Car): void {
|
||||
this.deletedCars$.next([...this.deletedCars$.value, entry.id]);
|
||||
this.messageService.add({
|
||||
severity: 'success',
|
||||
summary: 'Auto gelöscht',
|
||||
detail: 'Das Auto wurde erfolgreich gelöscht.',
|
||||
});
|
||||
}
|
||||
|
||||
private handleGetCarsError(error: unknown): Observable<never> {
|
||||
if (!(error instanceof HttpErrorResponse)) {
|
||||
return throwError(() => new Error('An unexpected error occurred'));
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case error.status >= 500 && error.status <= 599:
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Serverfehler',
|
||||
detail:
|
||||
'Beim Abrufen der Einträge ist ein Fehler aufgetreten. Bitte versuche es erneut.',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.error(error);
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Unerwarteter Fehler',
|
||||
detail:
|
||||
'Beim Abrufen der Einträge hat der Server eine unerwartete Antwort zurückgegeben.',
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<p-confirmDialog></p-confirmDialog>
|
||||
|
||||
<div class="flex rounded-border shadow">
|
||||
<div class="grow p-4 pos-relative edit-button" (click)="navigateToEdit()" role="button"
|
||||
aria-roledescription="Bearbeite diesen Eintrag">
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
|
||||
<div class="col-span-4 sm:col-span-2 md:col-span-1 flex my-auto items-center justify-center">
|
||||
<div class="flex gap-2 items-center">
|
||||
<ng-icon name="matDirectionsCarOutline" />
|
||||
<div>{{ car().name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-red-500 text-white rounded-r text-center flex flex-col justify-center">
|
||||
<button type="button" title="Löschen" class="reset cursor-pointer primary-color-text p-4 h-full rounded-r"
|
||||
(click)="confirmDeleteCar()">
|
||||
<ng-icon name="matDeleteSharp"></ng-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
.edit-button {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, DestroyRef, inject, input, output } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
||||
import {
|
||||
matDirectionsCarOutline,
|
||||
} from '@ng-icons/material-icons/outline';
|
||||
import {
|
||||
matDeleteSharp
|
||||
} from '@ng-icons/material-icons/sharp';
|
||||
import { CarClient } from '@vegasco-web/api/cars/car-client';
|
||||
import { RoutingService } from '@vegasco-web/services/routing.service';
|
||||
import { ConfirmationService, MessageService } from 'primeng/api';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { CardModule } from 'primeng/card';
|
||||
import { ConfirmDialogModule } from 'primeng/confirmdialog';
|
||||
import { catchError, EMPTY, Observable, tap, throwError } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-car-card',
|
||||
imports: [
|
||||
ButtonModule,
|
||||
CardModule,
|
||||
ConfirmDialogModule,
|
||||
NgIconComponent,
|
||||
],
|
||||
providers: [
|
||||
provideIcons({
|
||||
matDeleteSharp,
|
||||
matDirectionsCarOutline,
|
||||
}),
|
||||
ConfirmationService,
|
||||
],
|
||||
templateUrl: './car-card.component.html',
|
||||
styleUrl: './car-card.component.scss'
|
||||
})
|
||||
export class CarCardComponent {
|
||||
readonly car = input.required<Car>();
|
||||
|
||||
readonly carDeleted = output<Car>();
|
||||
|
||||
private readonly routingService = inject(RoutingService);
|
||||
private readonly carClient = inject(CarClient);
|
||||
private readonly messageService = inject(MessageService);
|
||||
private readonly confirmationService = inject(ConfirmationService);
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
async navigateToEdit(): Promise<void> {
|
||||
await this.routingService.navigateToEditCar(this.car().id);
|
||||
}
|
||||
|
||||
confirmDeleteCar(): void {
|
||||
this.confirmationService.confirm({
|
||||
closeOnEscape: true,
|
||||
dismissableMask: true,
|
||||
header: 'Bist du sicher?',
|
||||
message: `Möchtest du das Auto "${this.car().name}" wirklich löschen?`,
|
||||
acceptButtonProps: {
|
||||
label: 'Löschen',
|
||||
severity: 'danger',
|
||||
},
|
||||
rejectButtonProps: {
|
||||
label: 'Abbrechen',
|
||||
outlined: true,
|
||||
},
|
||||
accept: () => this.deleteCar(),
|
||||
});
|
||||
}
|
||||
|
||||
deleteCar(): void {
|
||||
this.carClient.delete(this.car().id)
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
tap(() => this.carDeleted.emit(this.car())),
|
||||
catchError((error) => this.handleError(error)),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private handleError(error: unknown): Observable<never> {
|
||||
if (!(error instanceof HttpErrorResponse)) {
|
||||
return throwError(() => error);
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case error.status >= 500 && error.status <= 599:
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Serverfehler',
|
||||
detail:
|
||||
'Beim Löschen des Autos ist ein Fehler aufgetreten. Bitte versuche es erneut.',
|
||||
});
|
||||
break;
|
||||
case error.status === 400:
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Clientfehler',
|
||||
detail:
|
||||
'Die Anwendung scheint falsche Daten an den Server zu senden.',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.error(error);
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Unerwarteter Fehler',
|
||||
detail:
|
||||
'Beim Löschen des Autos hat der Server eine unerwartete Antwort zurückgegeben.',
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<span class="required">*</span>
|
||||
@@ -0,0 +1,3 @@
|
||||
.required {
|
||||
color: red;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-required-marker',
|
||||
imports: [
|
||||
],
|
||||
templateUrl: './required-marker.component.html',
|
||||
styleUrl: './required-marker.component.scss'
|
||||
})
|
||||
export class RequiredMarkerComponent {
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
@if (!isCarDataLoaded()) {
|
||||
<div class="flex flex-col gap-6">
|
||||
<p-skeleton height="3.5rem" />
|
||||
<div class="flex flex-row gap-4">
|
||||
<p-skeleton height="3.5rem" width="10rem" />
|
||||
<p-skeleton height="3.5rem" width="10rem" />
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
<form [formGroup]="formGroup" class="flex flex-col gap-4" (ngSubmit)="onSubmit()">
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<label [for]="formFieldNames.name">
|
||||
Name
|
||||
<app-required-marker />
|
||||
</label>
|
||||
<input
|
||||
id="name"
|
||||
placeholder="Name eingeben"
|
||||
type="text"
|
||||
pInputText
|
||||
[formControlName]="formFieldNames.name" />
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<p-button type="button" label="Abbrechen" (click)="navigateToOverviewPage()" severity="warn" />
|
||||
<p-button type="submit" label="Abschicken" severity="success" [disabled]="formGroup.invalid" />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
import { HttpErrorResponse } from '@angular/common/http';
|
||||
import { Component, DestroyRef, inject, input, OnInit, signal } from '@angular/core';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { CarClient } from '@vegasco-web/api/cars/car-client';
|
||||
import { RoutingService } from '@vegasco-web/services/routing.service';
|
||||
import { MessageService } from 'primeng/api';
|
||||
import { ButtonModule } from 'primeng/button';
|
||||
import { ChipModule } from 'primeng/chip';
|
||||
import { DatePickerModule } from 'primeng/datepicker';
|
||||
import { FloatLabelModule } from 'primeng/floatlabel';
|
||||
import { InputGroupModule } from 'primeng/inputgroup';
|
||||
import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
|
||||
import { InputNumberModule } from 'primeng/inputnumber';
|
||||
import { InputTextModule } from 'primeng/inputtext';
|
||||
import { MultiSelectModule } from 'primeng/multiselect';
|
||||
import { SelectModule } from 'primeng/select';
|
||||
import { SkeletonModule } from 'primeng/skeleton';
|
||||
import { catchError, EMPTY, Observable, switchMap, tap, throwError } from 'rxjs';
|
||||
import { RequiredMarkerComponent } from './components/required-marker.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-entry',
|
||||
imports: [
|
||||
ButtonModule,
|
||||
ChipModule,
|
||||
DatePickerModule,
|
||||
FloatLabelModule,
|
||||
InputGroupAddonModule,
|
||||
InputGroupModule,
|
||||
InputNumberModule,
|
||||
InputTextModule,
|
||||
MultiSelectModule,
|
||||
ReactiveFormsModule,
|
||||
RequiredMarkerComponent,
|
||||
SelectModule,
|
||||
SkeletonModule,
|
||||
],
|
||||
templateUrl: './edit-car.component.html',
|
||||
styleUrl: './edit-car.component.scss'
|
||||
})
|
||||
export class EditCarComponent implements OnInit {
|
||||
private readonly carClient = inject(CarClient);
|
||||
private readonly routingService = inject(RoutingService);
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private readonly messageService = inject(MessageService);
|
||||
|
||||
protected readonly id = input<string | undefined>(undefined);
|
||||
|
||||
protected readonly today = new Date();
|
||||
|
||||
protected readonly formFieldNames = {
|
||||
name: 'name',
|
||||
} as const;
|
||||
|
||||
protected readonly formGroup = new FormGroup({
|
||||
[this.formFieldNames.name]: new FormControl<string | null>({ value: null, disabled: true }, [Validators.required]),
|
||||
});
|
||||
|
||||
protected readonly isCarDataLoaded = signal(false);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadEntryDetailsAndEnableControls();
|
||||
}
|
||||
|
||||
private loadEntryDetailsAndEnableControls() {
|
||||
const carId = this.id();
|
||||
|
||||
if (carId === undefined || carId === null) {
|
||||
this.enableFormControls();
|
||||
this.isCarDataLoaded.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
this.carClient
|
||||
.getSingle(carId)
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
catchError((error) => this.handleGetError(error)),
|
||||
tap((car) => {
|
||||
this.formGroup.patchValue({
|
||||
[this.formFieldNames.name]: car.name,
|
||||
});
|
||||
}),
|
||||
tap(() => {
|
||||
this.enableFormControls();
|
||||
this.isCarDataLoaded.set(true);
|
||||
}),
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
}
|
||||
|
||||
private enableFormControls(): void {
|
||||
for (const controlName of Object.values(this.formFieldNames)) {
|
||||
const control = this.formGroup.get(controlName);
|
||||
if (control) {
|
||||
control.enable();
|
||||
} else {
|
||||
console.warn(`Form control '${controlName}' not found.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async navigateToOverviewPage(): Promise<void> {
|
||||
await this.routingService.navigateToCars();
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.formGroup.invalid) {
|
||||
this.formGroup.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
var carId = this.id();
|
||||
if (carId === undefined || carId === null) {
|
||||
this.createCar();
|
||||
return;
|
||||
}
|
||||
|
||||
this.updateCar(carId);
|
||||
}
|
||||
|
||||
private getFormData() {
|
||||
return {
|
||||
name: this.formGroup.controls[this.formFieldNames.name].value!,
|
||||
};
|
||||
}
|
||||
|
||||
createCar() {
|
||||
var request: CreateCarRequest = this.getFormData();
|
||||
this.carClient.create(request)
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
catchError((error) => this.handleCreateOrUpdateError(error, false)),
|
||||
switchMap(() => this.routingService.navigateToCars())
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
updateCar(id: string) {
|
||||
var request: UpdateCarRequest = this.getFormData();
|
||||
this.carClient.update(id, request)
|
||||
.pipe(
|
||||
takeUntilDestroyed(this.destroyRef),
|
||||
catchError((error) => this.handleCreateOrUpdateError(error, true)),
|
||||
switchMap(() => this.routingService.navigateToCars())
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private handleGetError(error: unknown): Observable<never> {
|
||||
if (!(error instanceof HttpErrorResponse)) {
|
||||
return throwError(() => error);
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case error.status >= 500 && error.status <= 599:
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Serverfehler',
|
||||
detail:
|
||||
'Beim Abrufen des Autos ist ein Fehler aufgetreten. Bitte versuche es erneut.',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.error(error);
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Unerwarteter Fehler',
|
||||
detail:
|
||||
'Beim Abrufen des Autos hat der Server eine unerwartete Antwort zurückgegeben.',
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
private handleCreateOrUpdateError(error: unknown, isUpdate: boolean): Observable<never> {
|
||||
if (!(error instanceof HttpErrorResponse)) {
|
||||
return throwError(() => error);
|
||||
}
|
||||
|
||||
const action = isUpdate ? 'Aktualisieren' : 'Erstellen';
|
||||
|
||||
switch (true) {
|
||||
case error.status >= 500 && error.status <= 599:
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Serverfehler',
|
||||
detail:
|
||||
`Beim ${action} des Eintrags ist ein Fehler aufgetreten. Bitte versuche es erneut.`,
|
||||
});
|
||||
break;
|
||||
case error.status === 400:
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Clientfehler',
|
||||
detail:
|
||||
'Die Anwendung scheint falsche Daten an den Server zu senden.',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.error(error);
|
||||
this.messageService.add({
|
||||
severity: 'error',
|
||||
summary: 'Unerwarteter Fehler',
|
||||
detail:
|
||||
`Beim ${action} des Eintrags hat der Server eine unerwartete Antwort zurückgegeben.`,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
return EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -169,6 +169,11 @@ export class EditEntryComponent implements OnInit {
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.formGroup.invalid) {
|
||||
this.formGroup.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
var entryId = this.id();
|
||||
if (entryId === undefined || entryId === null) {
|
||||
this.createEntry();
|
||||
|
||||
@@ -18,4 +18,16 @@ export class RoutingService {
|
||||
async navigateToCreateEntry(): Promise<void> {
|
||||
await this.router.navigate(['entries', 'create']);
|
||||
}
|
||||
|
||||
async navigateToCars(): Promise<void> {
|
||||
await this.router.navigateByUrl('/cars');
|
||||
}
|
||||
|
||||
async navigateToEditCar(entryId: string): Promise<void> {
|
||||
await this.router.navigate(['cars', 'edit', entryId]);
|
||||
}
|
||||
|
||||
async navigateToCreateCar(): Promise<void> {
|
||||
await this.router.navigate(['cars', 'create']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user