From 3660c941ac40a395ee3b0ee33e3e1db141855612 Mon Sep 17 00:00:00 2001 From: marc-i Date: Thu, 14 May 2026 15:37:38 +0200 Subject: [PATCH] defragment --- README.md | 18 +- src/app/app.component.css | 159 ------------------ src/app/app.component.html | 122 +++----------- src/app/app.component.ts | 19 ++- src/app/core/models/todo.model.ts | 14 ++ src/app/{ => core/services}/todo.service.ts | 35 +--- .../error-message/error-message.component.css | 19 +++ .../error-message.component.html | 4 + .../error-message/error-message.component.ts | 12 ++ .../loading-indicator.component.css | 5 + .../loading-indicator.component.html | 1 + .../loading-indicator.component.ts | 11 ++ .../todo-form/todo-form.component.css | 40 +++++ .../todo-form/todo-form.component.html | 13 ++ .../todo-form/todo-form.component.ts | 21 +++ .../todo-item/todo-item.component.css | 56 ++++++ .../todo-item/todo-item.component.html | 18 ++ .../todo-item/todo-item.component.ts | 17 ++ .../todo-list/todo-list.component.css | 11 ++ .../todo-list/todo-list.component.html | 12 ++ .../todo-list/todo-list.component.ts | 18 ++ .../todo-pagination.component.css | 30 ++++ .../todo-pagination.component.html | 11 ++ .../todo-pagination.component.ts | 16 ++ src/app/todo.model.ts | 19 --- 25 files changed, 386 insertions(+), 315 deletions(-) create mode 100644 src/app/core/models/todo.model.ts rename src/app/{ => core/services}/todo.service.ts (66%) create mode 100644 src/app/features/todos/components/error-message/error-message.component.css create mode 100644 src/app/features/todos/components/error-message/error-message.component.html create mode 100644 src/app/features/todos/components/error-message/error-message.component.ts create mode 100644 src/app/features/todos/components/loading-indicator/loading-indicator.component.css create mode 100644 src/app/features/todos/components/loading-indicator/loading-indicator.component.html create mode 100644 src/app/features/todos/components/loading-indicator/loading-indicator.component.ts create mode 100644 src/app/features/todos/components/todo-form/todo-form.component.css create mode 100644 src/app/features/todos/components/todo-form/todo-form.component.html create mode 100644 src/app/features/todos/components/todo-form/todo-form.component.ts create mode 100644 src/app/features/todos/components/todo-item/todo-item.component.css create mode 100644 src/app/features/todos/components/todo-item/todo-item.component.html create mode 100644 src/app/features/todos/components/todo-item/todo-item.component.ts create mode 100644 src/app/features/todos/components/todo-list/todo-list.component.css create mode 100644 src/app/features/todos/components/todo-list/todo-list.component.html create mode 100644 src/app/features/todos/components/todo-list/todo-list.component.ts create mode 100644 src/app/features/todos/components/todo-pagination/todo-pagination.component.css create mode 100644 src/app/features/todos/components/todo-pagination/todo-pagination.component.html create mode 100644 src/app/features/todos/components/todo-pagination/todo-pagination.component.ts delete mode 100644 src/app/todo.model.ts diff --git a/README.md b/README.md index aef515e..4c65441 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,21 @@ WebDev-Angular-ToDo-Example/ ├── main.ts ← App-Bootstrap (Startpunkt) ├── styles.css ← Globale CSS-Basis-Styles └── app/ - ├── app.component.ts ← Root-Komponente (UI + Logik) - ├── todo.model.ts ← TypeScript-Interfaces (Datentypen) - └── todo.service.ts ← Service für API-Kommunikation + ├── app.component.ts / .html / .css + ├── core/ + │ ├── models/ + │ │ └── todo.model.ts + │ └── services/ + │ └── todo.service.ts + └── features/ + └── todos/ + └── components/ + ├── error-message/ + ├── loading-indicator/ + ├── todo-form/ + ├── todo-item/ + ├── todo-list/ + └── todo-pagination/ ``` ## Installation & Start diff --git a/src/app/app.component.css b/src/app/app.component.css index 585d441..8b0fa46 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -20,162 +20,3 @@ font-size: 0.85rem; margin: 0.25rem 0 0; } - -/* ── Fehlermeldung ───────────────────────────────────── */ -.error-box { - display: flex; - justify-content: space-between; - align-items: center; - background: #fee2e2; - border: 1px solid #fca5a5; - color: #b91c1c; - padding: 0.75rem 1rem; - border-radius: 8px; - margin-bottom: 1rem; -} -.close-btn { - background: none; - border: none; - cursor: pointer; - color: #b91c1c; - font-size: 1rem; -} - -/* ── Formular ────────────────────────────────────────── */ -.add-form { - display: flex; - gap: 0.5rem; - margin-bottom: 1.5rem; -} -.add-form input { - flex: 1; - padding: 0.6rem 0.8rem; - border: 1px solid #d1d5db; - border-radius: 8px; - font-size: 1rem; - outline: none; - transition: border-color 0.2s; -} -.add-form input:focus { - border-color: #2563eb; -} -.add-form button { - padding: 0.6rem 1.2rem; - background: #2563eb; - color: #fff; - border: none; - border-radius: 8px; - font-size: 1rem; - cursor: pointer; - white-space: nowrap; - transition: background 0.2s; -} -.add-form button:hover:not(:disabled) { - background: #1d4ed8; -} -.add-form button:disabled { - opacity: 0.5; - cursor: default; -} - -/* ── Ladeindikator ───────────────────────────────────── */ -.loading { - text-align: center; - color: #6b7280; - padding: 2rem; -} - -/* ── ToDo-Liste ──────────────────────────────────────── */ -.todo-list { - list-style: none; - margin: 0; - padding: 0; - display: flex; - flex-direction: column; - gap: 0.5rem; -} -.empty-state { - text-align: center; - color: #9ca3af; - padding: 2rem; -} -.todo-item { - display: flex; - align-items: center; - gap: 0.75rem; - padding: 0.75rem 1rem; - background: #fff; - border: 1px solid #e5e7eb; - border-radius: 8px; - transition: background 0.15s; -} -.todo-item:hover { - background: #f9fafb; -} - -/* Abgehaktes ToDo: Text wird durchgestrichen und ausgegraut */ -.todo-item.completed .todo-title { - text-decoration: line-through; - color: #9ca3af; -} - -.todo-item input[type="checkbox"] { - width: 1.1rem; - height: 1.1rem; - cursor: pointer; - flex-shrink: 0; -} -.todo-title { - flex: 1; - cursor: pointer; -} -.user-badge { - font-size: 0.7rem; - color: #6b7280; - background: #f3f4f6; - border-radius: 99px; - padding: 0.15rem 0.5rem; - white-space: nowrap; -} -.delete-btn { - background: none; - border: none; - color: #d1d5db; - font-size: 1rem; - cursor: pointer; - padding: 0.25rem; - line-height: 1; - border-radius: 4px; - transition: color 0.15s; -} -.delete-btn:hover { - color: #ef4444; -} - -/* ── Pagination ──────────────────────────────────────── */ -.pagination { - display: flex; - justify-content: center; - align-items: center; - gap: 1rem; - margin-top: 1.5rem; -} -.pagination button { - padding: 0.5rem 1rem; - border: 1px solid #d1d5db; - background: #fff; - border-radius: 8px; - cursor: pointer; - transition: background 0.15s; -} -.pagination button:hover:not(:disabled) { - background: #f3f4f6; -} -.pagination button:disabled { - opacity: 0.4; - cursor: default; -} -.page-info { - color: #6b7280; - font-size: 0.9rem; -} diff --git a/src/app/app.component.html b/src/app/app.component.html index 2f530b8..67398f5 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -5,105 +5,35 @@

Angular 21 · Vite · REST-API

- -
- Fehler: {{ error }} - -
+ - -
- - -
+ - -
Daten werden geladen…
+ - -
    + - -
  • - Keine ToDos auf dieser Seite. -
  • - -
  • - - - - - - - - User {{ todo.userId }} - - - -
  • -
- - - + diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 07b5cf8..61f56be 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -11,9 +11,13 @@ import { ChangeDetectorRef, Component, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; // *ngIf, *ngFor, etc. -import { FormsModule } from '@angular/forms'; // [(ngModel)] Two-Way-Binding -import { TodoService } from './todo.service'; -import { Todo } from './todo.model'; +import { Todo } from './core/models/todo.model'; +import { TodoService } from './core/services/todo.service'; +import { ErrorMessageComponent } from './features/todos/components/error-message/error-message.component'; +import { LoadingIndicatorComponent } from './features/todos/components/loading-indicator/loading-indicator.component'; +import { TodoFormComponent } from './features/todos/components/todo-form/todo-form.component'; +import { TodoListComponent } from './features/todos/components/todo-list/todo-list.component'; +import { TodoPaginationComponent } from './features/todos/components/todo-pagination/todo-pagination.component'; @Component({ // selector: Wie diese Komponente im HTML eingebunden wird () @@ -23,7 +27,14 @@ import { Todo } from './todo.model'; standalone: true, // imports: Andere Angular-Module/Komponenten, die im Template verwendet werden - imports: [CommonModule, FormsModule], + imports: [ + CommonModule, + ErrorMessageComponent, + TodoFormComponent, + LoadingIndicatorComponent, + TodoListComponent, + TodoPaginationComponent, + ], // Template und Styles sind ausgelagert für bessere Wartbarkeit templateUrl: './app.component.html', diff --git a/src/app/core/models/todo.model.ts b/src/app/core/models/todo.model.ts new file mode 100644 index 0000000..d5cecea --- /dev/null +++ b/src/app/core/models/todo.model.ts @@ -0,0 +1,14 @@ +// todo.model.ts – TypeScript-Interfaces für die ToDo-Datenstrukturen + +export interface Todo { + id: number; + userId: number; + title: string; + completed: boolean; +} + +export interface TodoCreate { + userId: number; + title: string; + completed?: boolean; +} diff --git a/src/app/todo.service.ts b/src/app/core/services/todo.service.ts similarity index 66% rename from src/app/todo.service.ts rename to src/app/core/services/todo.service.ts index 051616e..20a6f9b 100644 --- a/src/app/todo.service.ts +++ b/src/app/core/services/todo.service.ts @@ -1,25 +1,11 @@ -// todo.service.ts – Service für die Kommunikation mit der REST-API -// -// Ein Angular-Service ist eine Klasse, die wiederverwendbare Logik enthält. -// @Injectable({ providedIn: 'root' }) registriert den Service als Singleton -// im gesamten App-Kontext (nur eine Instanz für die ganze Anwendung). -// -// API-Dokumentation (OpenAPI): https://webdev.iten-web.ch/10003/api/ -// -// Für diese App verwenden wir REST-Pfade im Best-Practice-Stil: -// Basis-URL: https://webdev.iten-web.ch/10003/api -// Beispiel: https://webdev.iten-web.ch/10003/api/todos?page=1&limit=10 - import { Injectable } from '@angular/core'; -import { Todo, TodoCreate } from './todo.model'; +import { Todo, TodoCreate } from '../models/todo.model'; -// Basis-URL der API. const API_BASE = 'https://webdev.iten-web.ch/10003/api'; const REQUEST_TIMEOUT_MS = 10000; @Injectable({ providedIn: 'root' }) export class TodoService { - private buildUrl(path: string, query: Record = {}): string { const normalizedPath = path.startsWith('/') ? path : `/${path}`; const url = new URL(`${API_BASE}${normalizedPath}`); @@ -54,8 +40,6 @@ export class TodoService { return response.json() as Promise; })(); - // Promise.race garantiert, dass der Aufruf auch dann endet, - // wenn fetch in seltenen Browser-/Extension-Faellen hängen bleibt. const timeoutPromise = new Promise((_, reject) => { timeoutId = window.setTimeout(() => { controller.abort(); @@ -76,18 +60,10 @@ export class TodoService { } } - /** - * Alle ToDos abrufen – GET /todos - * Unterstützt serverseitige Pagination (Seite + Einträge pro Seite). - */ async getTodos(page = 1, limit = 10): Promise { return this.request('/todos', undefined, { page, limit }); } - /** - * Neues ToDo anlegen – POST /todos - * Der Request-Body enthält userId und title (completed ist optional). - */ async createTodo(data: TodoCreate): Promise { return this.request('/todos', { method: 'POST', @@ -96,11 +72,6 @@ export class TodoService { }); } - /** - * ToDo teilweise aktualisieren – PATCH /todos/:id - * Nur die angegebenen Felder werden geändert (z. B. nur "completed"). - * Im Gegensatz zu PUT wird das Objekt nicht vollständig ersetzt. - */ async patchTodo(id: number, changes: Partial): Promise { return this.request(`/todos/${id}`, { method: 'PATCH', @@ -109,10 +80,6 @@ export class TodoService { }); } - /** - * ToDo löschen – DELETE /todos/:id - * Die API antwortet mit HTTP 204 (No Content) – kein Body. - */ async deleteTodo(id: number): Promise { await this.request(`/todos/${id}`, { method: 'DELETE', diff --git a/src/app/features/todos/components/error-message/error-message.component.css b/src/app/features/todos/components/error-message/error-message.component.css new file mode 100644 index 0000000..b069ff5 --- /dev/null +++ b/src/app/features/todos/components/error-message/error-message.component.css @@ -0,0 +1,19 @@ +.error-box { + display: flex; + justify-content: space-between; + align-items: center; + background: #fee2e2; + border: 1px solid #fca5a5; + color: #b91c1c; + padding: 0.75rem 1rem; + border-radius: 8px; + margin-bottom: 1rem; +} + +.close-btn { + background: none; + border: none; + cursor: pointer; + color: #b91c1c; + font-size: 1rem; +} diff --git a/src/app/features/todos/components/error-message/error-message.component.html b/src/app/features/todos/components/error-message/error-message.component.html new file mode 100644 index 0000000..706f78a --- /dev/null +++ b/src/app/features/todos/components/error-message/error-message.component.html @@ -0,0 +1,4 @@ +
+ Fehler: {{ message }} + +
diff --git a/src/app/features/todos/components/error-message/error-message.component.ts b/src/app/features/todos/components/error-message/error-message.component.ts new file mode 100644 index 0000000..7176230 --- /dev/null +++ b/src/app/features/todos/components/error-message/error-message.component.ts @@ -0,0 +1,12 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'app-error-message', + standalone: true, + templateUrl: './error-message.component.html', + styleUrl: './error-message.component.css', +}) +export class ErrorMessageComponent { + @Input({ required: true }) message = ''; + @Output() dismissed = new EventEmitter(); +} diff --git a/src/app/features/todos/components/loading-indicator/loading-indicator.component.css b/src/app/features/todos/components/loading-indicator/loading-indicator.component.css new file mode 100644 index 0000000..df00efb --- /dev/null +++ b/src/app/features/todos/components/loading-indicator/loading-indicator.component.css @@ -0,0 +1,5 @@ +.loading { + text-align: center; + color: #6b7280; + padding: 2rem; +} diff --git a/src/app/features/todos/components/loading-indicator/loading-indicator.component.html b/src/app/features/todos/components/loading-indicator/loading-indicator.component.html new file mode 100644 index 0000000..7ca7961 --- /dev/null +++ b/src/app/features/todos/components/loading-indicator/loading-indicator.component.html @@ -0,0 +1 @@ +
{{ text }}
diff --git a/src/app/features/todos/components/loading-indicator/loading-indicator.component.ts b/src/app/features/todos/components/loading-indicator/loading-indicator.component.ts new file mode 100644 index 0000000..b1efaaf --- /dev/null +++ b/src/app/features/todos/components/loading-indicator/loading-indicator.component.ts @@ -0,0 +1,11 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'app-loading-indicator', + standalone: true, + templateUrl: './loading-indicator.component.html', + styleUrl: './loading-indicator.component.css', +}) +export class LoadingIndicatorComponent { + @Input() text = 'Daten werden geladen...'; +} diff --git a/src/app/features/todos/components/todo-form/todo-form.component.css b/src/app/features/todos/components/todo-form/todo-form.component.css new file mode 100644 index 0000000..ce3ca98 --- /dev/null +++ b/src/app/features/todos/components/todo-form/todo-form.component.css @@ -0,0 +1,40 @@ +.add-form { + display: flex; + gap: 0.5rem; + margin-bottom: 1.5rem; +} + +.add-form input { + flex: 1; + padding: 0.6rem 0.8rem; + border: 1px solid #d1d5db; + border-radius: 8px; + font-size: 1rem; + outline: none; + transition: border-color 0.2s; +} + +.add-form input:focus { + border-color: #2563eb; +} + +.add-form button { + padding: 0.6rem 1.2rem; + background: #2563eb; + color: #fff; + border: none; + border-radius: 8px; + font-size: 1rem; + cursor: pointer; + white-space: nowrap; + transition: background 0.2s; +} + +.add-form button:hover:not(:disabled) { + background: #1d4ed8; +} + +.add-form button:disabled { + opacity: 0.5; + cursor: default; +} diff --git a/src/app/features/todos/components/todo-form/todo-form.component.html b/src/app/features/todos/components/todo-form/todo-form.component.html new file mode 100644 index 0000000..43669c6 --- /dev/null +++ b/src/app/features/todos/components/todo-form/todo-form.component.html @@ -0,0 +1,13 @@ +
+ + +
diff --git a/src/app/features/todos/components/todo-form/todo-form.component.ts b/src/app/features/todos/components/todo-form/todo-form.component.ts new file mode 100644 index 0000000..61b107f --- /dev/null +++ b/src/app/features/todos/components/todo-form/todo-form.component.ts @@ -0,0 +1,21 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { FormsModule } from '@angular/forms'; + +@Component({ + selector: 'app-todo-form', + standalone: true, + imports: [FormsModule], + templateUrl: './todo-form.component.html', + styleUrl: './todo-form.component.css', +}) +export class TodoFormComponent { + @Input() model = ''; + @Input() saving = false; + + @Output() modelChange = new EventEmitter(); + @Output() submitted = new EventEmitter(); + + onSubmit(): void { + this.submitted.emit(); + } +} diff --git a/src/app/features/todos/components/todo-item/todo-item.component.css b/src/app/features/todos/components/todo-item/todo-item.component.css new file mode 100644 index 0000000..6ce472c --- /dev/null +++ b/src/app/features/todos/components/todo-item/todo-item.component.css @@ -0,0 +1,56 @@ +.todo-item { + display: flex; + align-items: center; + gap: 0.75rem; + padding: 0.75rem 1rem; + background: #fff; + border: 1px solid #e5e7eb; + border-radius: 8px; + transition: background 0.15s; +} + +.todo-item:hover { + background: #f9fafb; +} + +.todo-item.completed .todo-title { + text-decoration: line-through; + color: #9ca3af; +} + +.todo-item input[type="checkbox"] { + width: 1.1rem; + height: 1.1rem; + cursor: pointer; + flex-shrink: 0; +} + +.todo-title { + flex: 1; + cursor: pointer; +} + +.user-badge { + font-size: 0.7rem; + color: #6b7280; + background: #f3f4f6; + border-radius: 99px; + padding: 0.15rem 0.5rem; + white-space: nowrap; +} + +.delete-btn { + background: none; + border: none; + color: #d1d5db; + font-size: 1rem; + cursor: pointer; + padding: 0.25rem; + line-height: 1; + border-radius: 4px; + transition: color 0.15s; +} + +.delete-btn:hover { + color: #ef4444; +} diff --git a/src/app/features/todos/components/todo-item/todo-item.component.html b/src/app/features/todos/components/todo-item/todo-item.component.html new file mode 100644 index 0000000..e37af85 --- /dev/null +++ b/src/app/features/todos/components/todo-item/todo-item.component.html @@ -0,0 +1,18 @@ +
+ + + + + User {{ todo.userId }} + + +
diff --git a/src/app/features/todos/components/todo-item/todo-item.component.ts b/src/app/features/todos/components/todo-item/todo-item.component.ts new file mode 100644 index 0000000..16b0a65 --- /dev/null +++ b/src/app/features/todos/components/todo-item/todo-item.component.ts @@ -0,0 +1,17 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Todo } from '../../../../core/models/todo.model'; + +@Component({ + selector: 'app-todo-item', + standalone: true, + imports: [CommonModule], + templateUrl: './todo-item.component.html', + styleUrl: './todo-item.component.css', +}) +export class TodoItemComponent { + @Input({ required: true }) todo!: Todo; + + @Output() toggled = new EventEmitter(); + @Output() deleted = new EventEmitter(); +} diff --git a/src/app/features/todos/components/todo-list/todo-list.component.css b/src/app/features/todos/components/todo-list/todo-list.component.css new file mode 100644 index 0000000..6473013 --- /dev/null +++ b/src/app/features/todos/components/todo-list/todo-list.component.css @@ -0,0 +1,11 @@ +.todo-list { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.empty-state { + text-align: center; + color: #9ca3af; + padding: 2rem; +} diff --git a/src/app/features/todos/components/todo-list/todo-list.component.html b/src/app/features/todos/components/todo-list/todo-list.component.html new file mode 100644 index 0000000..724a107 --- /dev/null +++ b/src/app/features/todos/components/todo-list/todo-list.component.html @@ -0,0 +1,12 @@ +
+
+ Keine ToDos auf dieser Seite. +
+ + +
diff --git a/src/app/features/todos/components/todo-list/todo-list.component.ts b/src/app/features/todos/components/todo-list/todo-list.component.ts new file mode 100644 index 0000000..eff3823 --- /dev/null +++ b/src/app/features/todos/components/todo-list/todo-list.component.ts @@ -0,0 +1,18 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Todo } from '../../../../core/models/todo.model'; +import { TodoItemComponent } from '../todo-item/todo-item.component'; + +@Component({ + selector: 'app-todo-list', + standalone: true, + imports: [CommonModule, TodoItemComponent], + templateUrl: './todo-list.component.html', + styleUrl: './todo-list.component.css', +}) +export class TodoListComponent { + @Input() todos: Todo[] = []; + + @Output() toggled = new EventEmitter(); + @Output() deleted = new EventEmitter(); +} diff --git a/src/app/features/todos/components/todo-pagination/todo-pagination.component.css b/src/app/features/todos/components/todo-pagination/todo-pagination.component.css new file mode 100644 index 0000000..611b2a5 --- /dev/null +++ b/src/app/features/todos/components/todo-pagination/todo-pagination.component.css @@ -0,0 +1,30 @@ +.pagination { + display: flex; + justify-content: center; + align-items: center; + gap: 1rem; + margin-top: 1.5rem; +} + +.pagination button { + padding: 0.5rem 1rem; + border: 1px solid #d1d5db; + background: #fff; + border-radius: 8px; + cursor: pointer; + transition: background 0.15s; +} + +.pagination button:hover:not(:disabled) { + background: #f3f4f6; +} + +.pagination button:disabled { + opacity: 0.4; + cursor: default; +} + +.page-info { + color: #6b7280; + font-size: 0.9rem; +} diff --git a/src/app/features/todos/components/todo-pagination/todo-pagination.component.html b/src/app/features/todos/components/todo-pagination/todo-pagination.component.html new file mode 100644 index 0000000..8c80262 --- /dev/null +++ b/src/app/features/todos/components/todo-pagination/todo-pagination.component.html @@ -0,0 +1,11 @@ + diff --git a/src/app/features/todos/components/todo-pagination/todo-pagination.component.ts b/src/app/features/todos/components/todo-pagination/todo-pagination.component.ts new file mode 100644 index 0000000..bb71384 --- /dev/null +++ b/src/app/features/todos/components/todo-pagination/todo-pagination.component.ts @@ -0,0 +1,16 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'app-todo-pagination', + standalone: true, + templateUrl: './todo-pagination.component.html', + styleUrl: './todo-pagination.component.css', +}) +export class TodoPaginationComponent { + @Input() currentPage = 1; + @Input() canGoPrevious = false; + @Input() canGoNext = false; + + @Output() previous = new EventEmitter(); + @Output() next = new EventEmitter(); +} diff --git a/src/app/todo.model.ts b/src/app/todo.model.ts deleted file mode 100644 index 6f6db63..0000000 --- a/src/app/todo.model.ts +++ /dev/null @@ -1,19 +0,0 @@ -// todo.model.ts – TypeScript-Interfaces für die ToDo-Datenstrukturen -// -// Interfaces beschreiben den Aufbau von Objekten zur Compile-Zeit. -// Sie erzeugen keinen JavaScript-Code, sondern dienen nur der Typprüfung. - -/** Ein vollständiges ToDo-Objekt, wie es die API zurückgibt */ -export interface Todo { - id: number; // Eindeutige ID (von der API vergeben) - userId: number; // ID des Benutzers, dem das ToDo gehört - title: string; // Titel / Beschreibung des ToDos - completed: boolean; // Erledigt-Status -} - -/** Daten zum Erstellen eines neuen ToDos (id wird von der API gesetzt) */ -export interface TodoCreate { - userId: number; - title: string; - completed?: boolean; // Optional: Standard ist false -}