Skip to content

Commit 98ee155

Browse files
committed
Improve behavior-subject on examples-angular
1 parent 34324fe commit 98ee155

27 files changed

+27957
-74
lines changed
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
<h1>angular-rxjs</h1>
1+
<h1>angular-behavior-subject</h1>
22

3-
<p>Compteur : {{ count$ | async }}</p>
4-
<p>Double : {{ double$ | async }}</p>
3+
<p>Compteur : {{ counter$ | async }}</p>
54

6-
<button (click)="dec()">-10</button>
7-
<button (click)="inc()">+10</button>
8-
<button (click)="reset()">Reset</button>
5+
<button (click)="dec()">Dec</button>
6+
<button (click)="inc()">Inc</button>
7+
8+
<app-counter></app-counter>
9+
<app-label></app-label>
Lines changed: 35 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,58 @@
1-
import { Component } from '@angular/core'
2-
import { AsyncPipe, CommonModule } from '@angular/common'
3-
import { BehaviorSubject, map, Observable } from 'rxjs'
1+
import { Component, OnDestroy } from '@angular/core'
2+
import { CommonModule, AsyncPipe } from '@angular/common'
3+
import { BehaviorSubject, Subscription } from 'rxjs'
4+
import { CounterComponent } from './counter'
5+
import { LabelComponent } from './label'
46

57
@Component({
68
selector: 'app-root',
79
standalone: true,
8-
imports: [CommonModule, AsyncPipe],
9-
templateUrl: './app.html',
10-
styleUrls: ['./app.css']
10+
imports: [CommonModule, AsyncPipe, CounterComponent, LabelComponent],
11+
templateUrl: './app.html'
1112
})
12-
export class App {
13-
private readonly countSubject = new BehaviorSubject<number>(0)
13+
export class App implements OnDestroy {
14+
counter = new BehaviorSubject<number>(0)
15+
counter$ = this.counter.asObservable()
16+
private sub: Subscription
1417

15-
readonly count$: Observable<number> = this.countSubject.asObservable()
16-
readonly double$: Observable<number> = this.count$.pipe(map(v => v * 2))
18+
constructor() {
19+
this.sub = this.counter$.subscribe(v => console.log('Subscriber A:', v))
20+
}
1721

18-
inc(): void {
19-
this.countSubject.next(this.countSubject.value + 10)
22+
inc() {
23+
this.counter.next(this.counter.value + 1)
2024
}
2125

22-
dec(): void {
23-
this.countSubject.next(this.countSubject.value - 10)
26+
dec() {
27+
this.counter.next(this.counter.value - 1)
2428
}
2529

26-
reset(): void {
27-
this.countSubject.next(0)
30+
ngOnDestroy() {
31+
this.sub.unsubscribe()
2832
}
2933
}
3034

3135

3236

33-
// import { Component } from '@angular/core'
34-
// import { BehaviorSubject, map, Observable } from 'rxjs'
35-
36-
// @Component({
37-
// selector: 'app-root',
38-
// templateUrl: './app.html',
39-
// styleUrls: ['./app.css']
40-
// })
41-
// export class App {
42-
// private readonly countSubject = new BehaviorSubject<number>(0)
43-
44-
// readonly count$: Observable<number> = this.countSubject.asObservable()
45-
// readonly double$: Observable<number> = this.count$.pipe(map(v => v * 2))
46-
47-
// inc(): void {
48-
// this.countSubject.next(this.countSubject.value + 10)
49-
// }
50-
51-
// dec(): void {
52-
// this.countSubject.next(this.countSubject.value - 10)
53-
// }
54-
55-
// reset(): void {
56-
// this.countSubject.next(0)
57-
// }
58-
// }
59-
60-
61-
62-
// import { Component } from '@angular/core';
63-
// import { BehaviorSubject, map } from 'rxjs';
37+
// import { Component, OnDestroy } from '@angular/core'
38+
// import { CommonModule, AsyncPipe } from '@angular/common'
39+
// import { BehaviorSubject, Subscription } from 'rxjs'
40+
// import { CounterComponent } from './counter'
41+
// import { LabelComponent } from './label'
6442

6543
// @Component({
6644
// selector: 'app-root',
67-
// templateUrl: './app.html',
68-
// styleUrls: ['./app.css']
45+
// standalone: true,
46+
// imports: [CommonModule, AsyncPipe, CounterComponent, LabelComponent],
47+
// templateUrl: './app.html'
6948
// })
70-
// export class AppComponent {
71-
// count$ = new BehaviorSubject<number>(0);
72-
// double$ = this.count$.pipe(map(v => v * 2));
73-
74-
// inc() {
75-
// this.count$.next(this.count$.value + 10);
76-
// }
49+
// export class App implements OnDestroy {
50+
// counter = new BehaviorSubject<number>(0)
51+
// counter$ = this.counter.asObservable()
52+
// private sub: Subscription = this.counter$.subscribe(v => console.log('Subscriber A:', v))
7753

78-
// dec() {
79-
// this.count$.next(this.count$.value - 10);
80-
// }
54+
// inc() { this.counter.next(this.counter.value + 1) }
55+
// dec() { this.counter.next(this.counter.value - 1) }
8156

82-
// reset() {
83-
// this.count$.next(0);
84-
// }
85-
86-
// constructor() {
87-
// console.log('00000000001:', this.count$);
88-
// this.double$.subscribe();
89-
// }
57+
// ngOnDestroy() { this.sub.unsubscribe() }
9058
// }
91-
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<h2>Compteur</h2>
2+
3+
<p>Compteur : {{ count$ | async }}</p>
4+
<p>Double : {{ double$ | async }}</p>
5+
6+
<button (click)="dec()">-10</button>
7+
<button (click)="inc()">+10</button>
8+
<button (click)="reset()">Reset</button>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Injectable } from '@angular/core'
2+
import { BehaviorSubject } from 'rxjs'
3+
4+
@Injectable({ providedIn: 'root' })
5+
export class CounterService {
6+
private readonly countSubject = new BehaviorSubject<number>(0)
7+
readonly count$ = this.countSubject.asObservable()
8+
9+
inc(): void {
10+
this.countSubject.next(this.countSubject.value + 1)
11+
}
12+
13+
dec(): void {
14+
this.countSubject.next(this.countSubject.value - 1)
15+
}
16+
17+
reset(): void {
18+
this.countSubject.next(0)
19+
}
20+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Component } from '@angular/core'
2+
import { CommonModule } from '@angular/common'
3+
import { CounterService } from './counter.service'
4+
5+
@Component({
6+
selector: 'app-counter',
7+
standalone: true,
8+
imports: [CommonModule],
9+
template: `
10+
<p>Éditeur de compteur</p>
11+
<button (click)="dec()">-</button>
12+
<button (click)="inc()">+</button>
13+
<button (click)="reset()">Reset</button>
14+
`
15+
})
16+
export class CounterComponent {
17+
constructor(private counter: CounterService) {}
18+
19+
inc() {
20+
this.counter.inc()
21+
}
22+
23+
dec() {
24+
this.counter.dec()
25+
}
26+
27+
reset() {
28+
this.counter.reset()
29+
}
30+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Component, OnInit, OnDestroy } from '@angular/core'
2+
import { CommonModule } from '@angular/common'
3+
import { CounterService } from './counter.service'
4+
import { Subscription } from 'rxjs'
5+
6+
@Component({
7+
selector: 'app-label',
8+
standalone: true,
9+
imports: [CommonModule],
10+
template: `<p>Valeur actuelle (label) : {{ value }}</p>`
11+
})
12+
export class LabelComponent implements OnInit, OnDestroy {
13+
value = 0
14+
private sub?: Subscription
15+
16+
constructor(private counter: CounterService) {}
17+
18+
ngOnInit() {
19+
this.sub = this.counter.count$.subscribe(v => {
20+
console.log('[LabelComponent] Nouvelle valeur =', v)
21+
this.value = v
22+
})
23+
}
24+
25+
ngOnDestroy() {
26+
this.sub?.unsubscribe()
27+
}
28+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import nx from '@nx/eslint-plugin';
2+
import baseConfig from '../../eslint.config.mjs';
3+
4+
export default [
5+
...baseConfig,
6+
...nx.configs['flat/angular'],
7+
...nx.configs['flat/angular-template'],
8+
{
9+
files: ['**/*.ts'],
10+
rules: {
11+
'@angular-eslint/directive-selector': [
12+
'error',
13+
{
14+
type: 'attribute',
15+
prefix: 'app',
16+
style: 'camelCase',
17+
},
18+
],
19+
'@angular-eslint/component-selector': [
20+
'error',
21+
{
22+
type: 'element',
23+
prefix: 'app',
24+
style: 'kebab-case',
25+
},
26+
],
27+
},
28+
},
29+
{
30+
files: ['**/*.html'],
31+
// Override or add rules here
32+
rules: {},
33+
},
34+
];
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export default {
2+
displayName: 'angular-ngrx',
3+
preset: '../../jest.preset.js',
4+
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
5+
coverageDirectory: '../../coverage/apps/angular-ngrx',
6+
transform: {
7+
'^.+\\.(ts|mjs|js|html)$': [
8+
'jest-preset-angular',
9+
{
10+
tsconfig: '<rootDir>/tsconfig.spec.json',
11+
stringifyContentPathRegex: '\\.(html|svg)$',
12+
},
13+
],
14+
},
15+
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
16+
snapshotSerializers: [
17+
'jest-preset-angular/build/serializers/no-ng-attributes',
18+
'jest-preset-angular/build/serializers/ng-snapshot',
19+
'jest-preset-angular/build/serializers/html-comment',
20+
],
21+
};
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{
2+
"name": "angular-ngrx",
3+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
4+
"projectType": "application",
5+
"prefix": "app",
6+
"sourceRoot": "apps/angular-ngrx/src",
7+
"tags": [],
8+
"targets": {
9+
"build": {
10+
"executor": "@angular/build:application",
11+
"outputs": ["{options.outputPath}"],
12+
"options": {
13+
"outputPath": "dist/apps/angular-ngrx",
14+
"browser": "apps/angular-ngrx/src/main.ts",
15+
"polyfills": ["zone.js"],
16+
"tsConfig": "apps/angular-ngrx/tsconfig.app.json",
17+
"assets": [
18+
{
19+
"glob": "**/*",
20+
"input": "apps/angular-ngrx/public"
21+
}
22+
],
23+
"styles": ["apps/angular-ngrx/src/styles.css"]
24+
},
25+
"configurations": {
26+
"production": {
27+
"budgets": [
28+
{
29+
"type": "initial",
30+
"maximumWarning": "500kb",
31+
"maximumError": "1mb"
32+
},
33+
{
34+
"type": "anyComponentStyle",
35+
"maximumWarning": "4kb",
36+
"maximumError": "8kb"
37+
}
38+
],
39+
"outputHashing": "all"
40+
},
41+
"development": {
42+
"optimization": false,
43+
"extractLicenses": false,
44+
"sourceMap": true
45+
}
46+
},
47+
"defaultConfiguration": "production"
48+
},
49+
"serve": {
50+
"continuous": true,
51+
"executor": "@angular/build:dev-server",
52+
"configurations": {
53+
"production": {
54+
"buildTarget": "angular-ngrx:build:production"
55+
},
56+
"development": {
57+
"buildTarget": "angular-ngrx:build:development"
58+
}
59+
},
60+
"defaultConfiguration": "development"
61+
},
62+
"extract-i18n": {
63+
"executor": "@angular/build:extract-i18n",
64+
"options": {
65+
"buildTarget": "angular-ngrx:build"
66+
}
67+
},
68+
"lint": {
69+
"executor": "@nx/eslint:lint"
70+
},
71+
"test": {
72+
"executor": "@nx/jest:jest",
73+
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
74+
"options": {
75+
"jestConfig": "apps/angular-ngrx/jest.config.ts",
76+
"tsConfig": "apps/angular-ngrx/tsconfig.spec.json"
77+
}
78+
},
79+
"serve-static": {
80+
"continuous": true,
81+
"executor": "@nx/web:file-server",
82+
"options": {
83+
"buildTarget": "angular-ngrx:build",
84+
"port": 4200,
85+
"staticFilePath": "dist/apps/angular-ngrx/browser",
86+
"spa": true
87+
}
88+
}
89+
}
90+
}
14.7 KB
Binary file not shown.

0 commit comments

Comments
 (0)