Compare commits

...

4 commits

Author SHA1 Message Date
17179b95f0 cange 2025-11-26 13:51:06 +01:00
90d8e08859 change angular version 20 to 21 2025-11-26 12:47:46 +01:00
883fcfb1a5 Change version angular 2025-11-26 12:34:09 +01:00
fec717628c Task 2025-11-26 11:48:06 +01:00
8 changed files with 2859 additions and 7181 deletions

View file

@ -57,3 +57,16 @@ Angular CLI does not come with an end-to-end testing framework by default. You c
## 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.
## Séquence 2 Logique réactive du flux de données
### 1. Structure du flux
- Le service `TaskService` utilise un **BehaviorSubject** pour stocker et diffuser la liste des tâches.
- Le composant `Home` sabonne à ce flux via `tasks$` et le **pipe async**.
### 2. Mise à jour des données
- La méthode `addTask()` ajoute une tâche puis appelle `next()` pour émettre la nouvelle liste.
- La méthode `removeTask()` supprime une tâche puis émet à nouveau la liste mise à jour.
- La vue est automatiquement réactualisée sans rechargement.
### 3. Points clés retenus
- Pas besoin dappeler `getTasks()` à chaque fois : la donnée est **vivante**.
- `| async` gère labonnement et le désabonnement automatiquement.
- Le flux reste cohérent entre le service et la vue.

View file

@ -11,7 +11,7 @@
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"builder": "@angular/build:application",
"options": {
"outputPath": "dist/task-board",
"index": "src/index.html",
@ -56,7 +56,7 @@
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"builder": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "TaskBoard:build:production"
@ -68,10 +68,10 @@
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n"
"builder": "@angular/build:extract-i18n"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"builder": "@angular/build:karma",
"options": {
"polyfills": [
"zone.js",
@ -95,5 +95,31 @@
},
"cli": {
"analytics": false
},
"schematics": {
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
}
}

9863
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -10,21 +10,21 @@
},
"private": true,
"dependencies": {
"@angular/common": "^19.2.0",
"@angular/compiler": "^19.2.0",
"@angular/core": "^19.2.0",
"@angular/forms": "^19.2.0",
"@angular/platform-browser": "^19.2.0",
"@angular/platform-browser-dynamic": "^19.2.0",
"@angular/router": "^19.2.0",
"@angular/common": "^21.0.1",
"@angular/compiler": "^21.0.1",
"@angular/core": "^21.0.1",
"@angular/forms": "^21.0.1",
"@angular/platform-browser": "^21.0.1",
"@angular/platform-browser-dynamic": "^21.0.1",
"@angular/router": "^21.0.1",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.15.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^19.2.11",
"@angular/cli": "^19.2.11",
"@angular/compiler-cli": "^19.2.0",
"@angular/build": "^21.0.0",
"@angular/cli": "^21.0.0",
"@angular/compiler-cli": "^21.0.1",
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.6.0",
"karma": "~6.4.0",
@ -32,6 +32,6 @@
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.7.2"
"typescript": "~5.9.3"
}
}

View file

@ -1 +1,19 @@
<p>home works!</p>
<h1>Home works!</h1>
<h2>Task List</h2>
@if (tasks$ | async; as tasks) {
<ul>
@for (task of tasks; track task) {
<li>
{{ task.title }}
</li>
}
</ul>
} @else {
<p>Loading tasks...</p>
}
<p>Elapsed time: <span style="font-family:monospace;font-size:1.2em">{{ elapsedClock }}</span></p>
<!-- Add a task -->
<button (click)="addTask('New Task')">+ Add a task</button>

View file

@ -1,11 +1,45 @@
import { Component } from '@angular/core';
import { Component, inject } from '@angular/core';
import { CommonModule, AsyncPipe } from '@angular/common';
import { TaskService } from '../../service/task.service';
@Component({
selector: 'app-home',
imports: [],
imports: [CommonModule, AsyncPipe],
templateUrl: './home.component.html',
styleUrl: './home.component.css'
})
export class HomeComponent {
protected count = 0;
private intervalId: any;
public elapsedClock: string = '';
private taskService = inject(TaskService);
tasks$ = this.taskService.tasks$;
ngOnInit() {
this.updateElapsedClock();
this.intervalId = setInterval(() => {
this.count++;
this.updateElapsedClock();
}, 500);
}
ngOnDestroy() {
if (this.intervalId) {
clearInterval(this.intervalId);
}
}
private updateElapsedClock() {
const totalSeconds = Math.floor(this.count / 2);
const h = String(Math.floor(totalSeconds / 3600)).padStart(2, '0');
const m = String(Math.floor((totalSeconds % 3600) / 60)).padStart(2, '0');
const s = String(totalSeconds % 60).padStart(2, '0');
this.elapsedClock = `${h}:${m}:${s}`;
}
addTask(title: string) {
this.taskService.addTask(title);
}
}

View file

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { TaskService } from './task.service';
describe('TaskService', () => {
let service: TaskService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(TaskService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View file

@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, of } from 'rxjs';
import { delay } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class TaskService {
private tasks = [
{ id: 1, title: 'Sample Task' },
{ id: 2, title: 'Another Task' },
{ id: 3, title: 'More Tasks' }
];
private nextId = this.tasks.length > 0 ? Math.max(...this.tasks.map(t => t.id)) + 1 : 1;
getTasks() {
return of(this.tasks).pipe(delay(1000));
}
private tasksSubject = new BehaviorSubject(this.tasks);
tasks$ = this.tasksSubject.asObservable();
addTask(title: string) {
const newTask = { id: this.nextId++, title: title.trim() };
this.tasks.push(newTask);
this.tasksSubject.next([...this.tasks]);
}
}