Compare commits
No commits in common. "17179b95f0f00c875f50220c69a887c31eeaba86" and "8e9bd1a6d0ccee5e0fbb1cbd125bfcedbe671576" have entirely different histories.
17179b95f0
...
8e9bd1a6d0
8 changed files with 7178 additions and 2856 deletions
13
README.md
13
README.md
|
|
@ -57,16 +57,3 @@ Angular CLI does not come with an end-to-end testing framework by default. You c
|
||||||
## Additional Resources
|
## 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.
|
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` s’abonne à 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 d’appeler `getTasks()` à chaque fois : la donnée est **vivante**.
|
|
||||||
- `| async` gère l’abonnement et le désabonnement automatiquement.
|
|
||||||
- Le flux reste cohérent entre le service et la vue.
|
|
||||||
34
angular.json
34
angular.json
|
|
@ -11,7 +11,7 @@
|
||||||
"prefix": "app",
|
"prefix": "app",
|
||||||
"architect": {
|
"architect": {
|
||||||
"build": {
|
"build": {
|
||||||
"builder": "@angular/build:application",
|
"builder": "@angular-devkit/build-angular:application",
|
||||||
"options": {
|
"options": {
|
||||||
"outputPath": "dist/task-board",
|
"outputPath": "dist/task-board",
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
"defaultConfiguration": "production"
|
"defaultConfiguration": "production"
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"builder": "@angular/build:dev-server",
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
"buildTarget": "TaskBoard:build:production"
|
"buildTarget": "TaskBoard:build:production"
|
||||||
|
|
@ -68,10 +68,10 @@
|
||||||
"defaultConfiguration": "development"
|
"defaultConfiguration": "development"
|
||||||
},
|
},
|
||||||
"extract-i18n": {
|
"extract-i18n": {
|
||||||
"builder": "@angular/build:extract-i18n"
|
"builder": "@angular-devkit/build-angular:extract-i18n"
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular/build:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
"polyfills": [
|
"polyfills": [
|
||||||
"zone.js",
|
"zone.js",
|
||||||
|
|
@ -95,31 +95,5 @@
|
||||||
},
|
},
|
||||||
"cli": {
|
"cli": {
|
||||||
"analytics": false
|
"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": "."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9859
package-lock.json
generated
9859
package-lock.json
generated
File diff suppressed because it is too large
Load diff
22
package.json
22
package.json
|
|
@ -10,21 +10,21 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/common": "^21.0.1",
|
"@angular/common": "^19.2.0",
|
||||||
"@angular/compiler": "^21.0.1",
|
"@angular/compiler": "^19.2.0",
|
||||||
"@angular/core": "^21.0.1",
|
"@angular/core": "^19.2.0",
|
||||||
"@angular/forms": "^21.0.1",
|
"@angular/forms": "^19.2.0",
|
||||||
"@angular/platform-browser": "^21.0.1",
|
"@angular/platform-browser": "^19.2.0",
|
||||||
"@angular/platform-browser-dynamic": "^21.0.1",
|
"@angular/platform-browser-dynamic": "^19.2.0",
|
||||||
"@angular/router": "^21.0.1",
|
"@angular/router": "^19.2.0",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.15.0"
|
"zone.js": "~0.15.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular/build": "^21.0.0",
|
"@angular-devkit/build-angular": "^19.2.11",
|
||||||
"@angular/cli": "^21.0.0",
|
"@angular/cli": "^19.2.11",
|
||||||
"@angular/compiler-cli": "^21.0.1",
|
"@angular/compiler-cli": "^19.2.0",
|
||||||
"@types/jasmine": "~5.1.0",
|
"@types/jasmine": "~5.1.0",
|
||||||
"jasmine-core": "~5.6.0",
|
"jasmine-core": "~5.6.0",
|
||||||
"karma": "~6.4.0",
|
"karma": "~6.4.0",
|
||||||
|
|
@ -32,6 +32,6 @@
|
||||||
"karma-coverage": "~2.2.0",
|
"karma-coverage": "~2.2.0",
|
||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "~2.1.0",
|
"karma-jasmine-html-reporter": "~2.1.0",
|
||||||
"typescript": "~5.9.3"
|
"typescript": "~5.7.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1 @@
|
||||||
<h1>Home works!</h1>
|
<p>home works!</p>
|
||||||
|
|
||||||
<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>
|
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,11 @@
|
||||||
|
import { Component } from '@angular/core';
|
||||||
import { Component, inject } from '@angular/core';
|
|
||||||
import { CommonModule, AsyncPipe } from '@angular/common';
|
|
||||||
import { TaskService } from '../../service/task.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
imports: [CommonModule, AsyncPipe],
|
imports: [],
|
||||||
templateUrl: './home.component.html',
|
templateUrl: './home.component.html',
|
||||||
styleUrl: './home.component.css'
|
styleUrl: './home.component.css'
|
||||||
})
|
})
|
||||||
export class HomeComponent {
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue