feat(doc): move pipe bug

This commit is contained in:
thomas
2023-10-18 09:55:10 +02:00
parent beae215911
commit 49d7a7f968
14 changed files with 14 additions and 14 deletions

View File

@@ -0,0 +1,36 @@
{
"extends": ["../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts"],
"extends": [
"plugin:@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:@nx/angular-template"],
"rules": {}
}
]
}

View File

@@ -0,0 +1,13 @@
# High Order Operator Bug
> Author: Thomas Laforge
### Run Application
```bash
npx nx serve rxjs-pipe-bug
```
### Documentation and Instruction
Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/rxjs/11-bug-chaining-operator/).

View File

@@ -0,0 +1,82 @@
{
"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": [],
"allowedCommonJsDependencies": ["seedrandom"]
},
"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": "@nx/linter:eslint",
"options": {
"lintFilePatterns": [
"apps/rxjs/pipe-bug/**/*.ts",
"apps/rxjs/pipe-bug/**/*.html"
]
}
}
},
"tags": []
}

View File

@@ -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: `
<button (click)="deleteTopic()"><ng-content></ng-content></button>
<div>{{ message$$ | async }}</div>
`,
})
export class ButtonDeleteComponent {
@Input() topic!: TopicType;
message$$ = new BehaviorSubject<string>('');
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: `
<div *ngFor="let item of all$ | async">
{{ item.id }} - {{ item.topic }}
</div>
<button-delete-topic topic="food">Delete Food</button-delete-topic>
<button-delete-topic topic="sport">Delete Sport</button-delete-topic>
<button-delete-topic topic="book">Delete Book</button-delete-topic>
`,
})
export class AppComponent {
private service = inject(AppService);
all$ = this.service.getAll$;
}

View File

@@ -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<boolean> {
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)
)
);
}
}

View File

@@ -0,0 +1,58 @@
/* eslint-disable @typescript-eslint/member-ordering */
import { randomError } from '@angular-challenges/shared/utils';
import { Injectable } from '@angular/core';
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<DBState> {
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) =>
randomError({
success: () => {
this.deleteOne(id);
return of(true);
},
error: () => of(false),
});
}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>RxjsPipeBug</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@@ -0,0 +1,4 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

View File

@@ -0,0 +1 @@
/* You can add global styles to this file, and also import other style files */

View File

@@ -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"]
}

View File

@@ -0,0 +1,7 @@
{
"extends": "./tsconfig.json",
"include": ["**/*.ts"],
"compilerOptions": {
"types": []
}
}

View File

@@ -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
}
}