diff --git a/apps/rxjs-pipe-bug/.eslintrc.json b/apps/rxjs-pipe-bug/.eslintrc.json
new file mode 100644
index 0000000..028ce09
--- /dev/null
+++ b/apps/rxjs-pipe-bug/.eslintrc.json
@@ -0,0 +1,36 @@
+{
+ "extends": ["../../.eslintrc.json"],
+ "ignorePatterns": ["!**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "extends": [
+ "plugin:@nrwl/nx/angular",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "type": "attribute",
+ "prefix": "app",
+ "style": "camelCase"
+ }
+ ],
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "type": "element",
+ "prefix": "app",
+ "style": "kebab-case"
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@nrwl/nx/angular-template"],
+ "rules": {}
+ }
+ ]
+}
diff --git a/apps/rxjs-pipe-bug/README.md b/apps/rxjs-pipe-bug/README.md
new file mode 100644
index 0000000..4b02cdf
--- /dev/null
+++ b/apps/rxjs-pipe-bug/README.md
@@ -0,0 +1,35 @@
+
Rxjs pipe bug
+
+> Author: Thomas Laforge
+
+
+
+### Information
+
+### Statement
+
+### Step 1
+
+### Step 2
+
+### Constraints:
+
+### Submitting your work
+
+1. Fork the project
+2. clone it
+3. npm install
+4. **nx serve rxjs-pipe-bug**
+5. _...work on it_
+6. Commit your work
+7. Submit a PR with a title beginning with **Answer:11** that I will review and other dev can review.
+
+
+
+
+
+
+
+
+_You can ask any question on_
diff --git a/apps/rxjs-pipe-bug/project.json b/apps/rxjs-pipe-bug/project.json
new file mode 100644
index 0000000..90b7abe
--- /dev/null
+++ b/apps/rxjs-pipe-bug/project.json
@@ -0,0 +1,81 @@
+{
+ "name": "rxjs-pipe-bug",
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
+ "projectType": "application",
+ "sourceRoot": "apps/rxjs-pipe-bug/src",
+ "prefix": "app",
+ "targets": {
+ "build": {
+ "executor": "@angular-devkit/build-angular:browser",
+ "outputs": ["{options.outputPath}"],
+ "options": {
+ "outputPath": "dist/apps/rxjs-pipe-bug",
+ "index": "apps/rxjs-pipe-bug/src/index.html",
+ "main": "apps/rxjs-pipe-bug/src/main.ts",
+ "polyfills": ["zone.js"],
+ "tsConfig": "apps/rxjs-pipe-bug/tsconfig.app.json",
+ "inlineStyleLanguage": "scss",
+ "assets": [
+ "apps/rxjs-pipe-bug/src/favicon.ico",
+ "apps/rxjs-pipe-bug/src/assets"
+ ],
+ "styles": ["apps/rxjs-pipe-bug/src/styles.scss"],
+ "scripts": []
+ },
+ "configurations": {
+ "production": {
+ "budgets": [
+ {
+ "type": "initial",
+ "maximumWarning": "500kb",
+ "maximumError": "1mb"
+ },
+ {
+ "type": "anyComponentStyle",
+ "maximumWarning": "2kb",
+ "maximumError": "4kb"
+ }
+ ],
+ "outputHashing": "all"
+ },
+ "development": {
+ "buildOptimizer": false,
+ "optimization": false,
+ "vendorChunk": true,
+ "extractLicenses": false,
+ "sourceMap": true,
+ "namedChunks": true
+ }
+ },
+ "defaultConfiguration": "production"
+ },
+ "serve": {
+ "executor": "@angular-devkit/build-angular:dev-server",
+ "configurations": {
+ "production": {
+ "browserTarget": "rxjs-pipe-bug:build:production"
+ },
+ "development": {
+ "browserTarget": "rxjs-pipe-bug:build:development"
+ }
+ },
+ "defaultConfiguration": "development"
+ },
+ "extract-i18n": {
+ "executor": "@angular-devkit/build-angular:extract-i18n",
+ "options": {
+ "browserTarget": "rxjs-pipe-bug:build"
+ }
+ },
+ "lint": {
+ "executor": "@nrwl/linter:eslint",
+ "options": {
+ "lintFilePatterns": [
+ "apps/rxjs-pipe-bug/**/*.ts",
+ "apps/rxjs-pipe-bug/**/*.html"
+ ]
+ }
+ }
+ },
+ "tags": []
+}
diff --git a/apps/rxjs-pipe-bug/src/app/app.component.ts b/apps/rxjs-pipe-bug/src/app/app.component.ts
new file mode 100644
index 0000000..b0c6951
--- /dev/null
+++ b/apps/rxjs-pipe-bug/src/app/app.component.ts
@@ -0,0 +1,56 @@
+/* eslint-disable @angular-eslint/component-selector */
+import { AsyncPipe, NgFor } from '@angular/common';
+import { Component, inject, Input } from '@angular/core';
+import { BehaviorSubject, take } from 'rxjs';
+import { AppService } from './app.service';
+import { TopicType } from './localDB.service';
+
+@Component({
+ standalone: true,
+ selector: 'button-delete-topic',
+ imports: [AsyncPipe],
+ template: `
+
+ {{ message$$ | async }}
+ `,
+})
+export class ButtonDeleteComponent {
+ @Input() topic!: TopicType;
+
+ message$$ = new BehaviorSubject('');
+
+ private service = inject(AppService);
+
+ deleteTopic() {
+ this.service
+ .deleteOldTopics(this.topic)
+ .pipe(take(1))
+ .subscribe((result) =>
+ this.message$$.next(
+ result
+ ? `All ${this.topic} have been deleted`
+ : `Error: deletion of some ${this.topic} failed`
+ )
+ );
+ }
+}
+
+@Component({
+ standalone: true,
+ imports: [AsyncPipe, NgFor, ButtonDeleteComponent],
+ selector: 'app-root',
+ template: `
+
+ {{ item.id }} - {{ item.topic }}
+
+
+ Delete Food
+ Delete Sport
+ Delete Book
+ `,
+})
+export class AppComponent {
+ private service = inject(AppService);
+
+ all$ = this.service.getAll$;
+}
diff --git a/apps/rxjs-pipe-bug/src/app/app.service.ts b/apps/rxjs-pipe-bug/src/app/app.service.ts
new file mode 100644
index 0000000..09a9ed1
--- /dev/null
+++ b/apps/rxjs-pipe-bug/src/app/app.service.ts
@@ -0,0 +1,23 @@
+import { inject, Injectable } from '@angular/core';
+import { merge, mergeMap, Observable, of, take } from 'rxjs';
+import { LocalDBService, TopicType } from './localDB.service';
+
+@Injectable({ providedIn: 'root' })
+export class AppService {
+ private dbService = inject(LocalDBService);
+
+ getAll$ = this.dbService.infos$;
+
+ deleteOldTopics(type: TopicType): Observable {
+ return this.dbService.searchByType(type).pipe(
+ take(1),
+ mergeMap((topicToDelete) =>
+ topicToDelete.length > 0
+ ? topicToDelete
+ .map((t) => this.dbService.deleteOneTopic(t.id))
+ .reduce((acc, curr) => merge(acc, curr), of(true))
+ : of(true)
+ )
+ );
+ }
+}
diff --git a/apps/rxjs-pipe-bug/src/app/localDB.service.ts b/apps/rxjs-pipe-bug/src/app/localDB.service.ts
new file mode 100644
index 0000000..710c62f
--- /dev/null
+++ b/apps/rxjs-pipe-bug/src/app/localDB.service.ts
@@ -0,0 +1,58 @@
+/* eslint-disable @typescript-eslint/member-ordering */
+import { Injectable } from '@angular/core';
+import { randNumber } from '@ngneat/falso';
+import { ComponentStore } from '@ngrx/component-store';
+import { of } from 'rxjs';
+
+export type TopicType = 'food' | 'book' | 'sport';
+
+interface Info {
+ id: number;
+ topic: TopicType;
+}
+
+interface DBState {
+ infos: Info[];
+}
+
+const initialState: DBState = {
+ infos: [
+ { id: 1, topic: 'book' },
+ { id: 2, topic: 'book' },
+ { id: 3, topic: 'book' },
+ { id: 4, topic: 'book' },
+ { id: 5, topic: 'food' },
+ { id: 6, topic: 'food' },
+ { id: 7, topic: 'book' },
+ { id: 8, topic: 'book' },
+ { id: 9, topic: 'book' },
+ { id: 10, topic: 'sport' },
+ ],
+};
+
+@Injectable({ providedIn: 'root' })
+export class LocalDBService extends ComponentStore {
+ constructor() {
+ super(initialState);
+ }
+
+ infos$ = this.select((state) => state.infos);
+
+ searchByType = (type: TopicType) =>
+ this.select((state) => state.infos.filter((i) => i.topic === type));
+
+ deleteOne = this.updater(
+ (state, id: number): DBState => ({
+ infos: state.infos.filter((i) => i.id !== id),
+ })
+ );
+
+ deleteOneTopic = (id: number) => {
+ const randomNumber = randNumber({ min: 0.1, max: 1, fraction: 2 });
+ if (randomNumber > 0.5) {
+ this.deleteOne(id);
+ return of(true);
+ }
+ return of(false);
+ };
+}
diff --git a/apps/rxjs-pipe-bug/src/assets/.gitkeep b/apps/rxjs-pipe-bug/src/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/apps/rxjs-pipe-bug/src/favicon.ico b/apps/rxjs-pipe-bug/src/favicon.ico
new file mode 100644
index 0000000..317ebcb
Binary files /dev/null and b/apps/rxjs-pipe-bug/src/favicon.ico differ
diff --git a/apps/rxjs-pipe-bug/src/index.html b/apps/rxjs-pipe-bug/src/index.html
new file mode 100644
index 0000000..caa71f3
--- /dev/null
+++ b/apps/rxjs-pipe-bug/src/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ RxjsPipeBug
+
+
+
+
+
+
+
+
diff --git a/apps/rxjs-pipe-bug/src/main.ts b/apps/rxjs-pipe-bug/src/main.ts
new file mode 100644
index 0000000..31c5da4
--- /dev/null
+++ b/apps/rxjs-pipe-bug/src/main.ts
@@ -0,0 +1,4 @@
+import { bootstrapApplication } from '@angular/platform-browser';
+import { AppComponent } from './app/app.component';
+
+bootstrapApplication(AppComponent).catch((err) => console.error(err));
diff --git a/apps/rxjs-pipe-bug/src/styles.scss b/apps/rxjs-pipe-bug/src/styles.scss
new file mode 100644
index 0000000..90d4ee0
--- /dev/null
+++ b/apps/rxjs-pipe-bug/src/styles.scss
@@ -0,0 +1 @@
+/* You can add global styles to this file, and also import other style files */
diff --git a/apps/rxjs-pipe-bug/tsconfig.app.json b/apps/rxjs-pipe-bug/tsconfig.app.json
new file mode 100644
index 0000000..e0e9bfb
--- /dev/null
+++ b/apps/rxjs-pipe-bug/tsconfig.app.json
@@ -0,0 +1,10 @@
+{
+ "extends": "./tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../../dist/out-tsc",
+ "types": []
+ },
+ "files": ["src/main.ts"],
+ "include": ["src/**/*.d.ts"],
+ "exclude": ["jest.config.ts", "**/*.test.ts", "**/*.spec.ts"]
+}
diff --git a/apps/rxjs-pipe-bug/tsconfig.editor.json b/apps/rxjs-pipe-bug/tsconfig.editor.json
new file mode 100644
index 0000000..0f9036b
--- /dev/null
+++ b/apps/rxjs-pipe-bug/tsconfig.editor.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["**/*.ts"],
+ "compilerOptions": {
+ "types": []
+ }
+}
diff --git a/apps/rxjs-pipe-bug/tsconfig.json b/apps/rxjs-pipe-bug/tsconfig.json
new file mode 100644
index 0000000..0b22c5f
--- /dev/null
+++ b/apps/rxjs-pipe-bug/tsconfig.json
@@ -0,0 +1,29 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.app.json"
+ },
+ {
+ "path": "./tsconfig.editor.json"
+ }
+ ],
+ "compilerOptions": {
+ "target": "es2022",
+ "useDefineForClassFields": false,
+ "forceConsistentCasingInFileNames": true,
+ "strict": true,
+ "noImplicitOverride": true,
+ "noPropertyAccessFromIndexSignature": true,
+ "noImplicitReturns": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "angularCompilerOptions": {
+ "enableI18nLegacyMessageIdFormat": false,
+ "strictInjectionParameters": true,
+ "strictInputAccessModifiers": true,
+ "strictTemplates": true
+ }
+}