mirror of
https://github.com/Raghu-Ch/angular-challenges.git
synced 2026-02-10 12:53:03 -05:00
Merge pull request #193 from DeveshChau/rxjs-catch-error
feat: challenge 38 - rxjs catch error
This commit is contained in:
@@ -24,7 +24,7 @@ If you would like to propose a challenge, this project is open source, so feel f
|
||||
|
||||
## Challenges
|
||||
|
||||
Check [all 37 challenges](https://angular-challenges.vercel.app/)
|
||||
Check [all 38 challenges](https://angular-challenges.vercel.app/)
|
||||
|
||||
## Contributors ✨
|
||||
|
||||
|
||||
36
apps/rxjs-catch-error/.eslintrc.json
Normal file
36
apps/rxjs-catch-error/.eslintrc.json
Normal file
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"rules": {
|
||||
"@angular-eslint/directive-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "attribute",
|
||||
"prefix": "app",
|
||||
"style": "camelCase"
|
||||
}
|
||||
],
|
||||
"@angular-eslint/component-selector": [
|
||||
"error",
|
||||
{
|
||||
"type": "element",
|
||||
"prefix": "app",
|
||||
"style": "kebab-case"
|
||||
}
|
||||
]
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@nx/angular",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
]
|
||||
},
|
||||
{
|
||||
"files": ["*.html"],
|
||||
"extends": ["plugin:@nx/angular-template"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
13
apps/rxjs-catch-error/README.md
Normal file
13
apps/rxjs-catch-error/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# catchError
|
||||
|
||||
> Author: Devesh Chaudhari
|
||||
|
||||
### Run Application
|
||||
|
||||
```bash
|
||||
npx nx serve rxjs-catch-error
|
||||
```
|
||||
|
||||
### Documentation and Instruction
|
||||
|
||||
Challenge documentation is [here](https://angular-challenges.vercel.app/challenges/rxjs/38-catch-error/).
|
||||
22
apps/rxjs-catch-error/jest.config.ts
Normal file
22
apps/rxjs-catch-error/jest.config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'rxjs-catch-error',
|
||||
preset: '../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
|
||||
coverageDirectory: '../../coverage/apps/rxjs-catch-error',
|
||||
transform: {
|
||||
'^.+\\.(ts|mjs|js|html)$': [
|
||||
'jest-preset-angular',
|
||||
{
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
stringifyContentPathRegex: '\\.(html|svg)$',
|
||||
},
|
||||
],
|
||||
},
|
||||
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/serializers/no-ng-attributes',
|
||||
'jest-preset-angular/build/serializers/ng-snapshot',
|
||||
'jest-preset-angular/build/serializers/html-comment',
|
||||
],
|
||||
};
|
||||
95
apps/rxjs-catch-error/project.json
Normal file
95
apps/rxjs-catch-error/project.json
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"name": "rxjs-catch-error",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"projectType": "application",
|
||||
"prefix": "app",
|
||||
"sourceRoot": "apps/rxjs-catch-error/src",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@angular-devkit/build-angular:browser",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/apps/rxjs-catch-error",
|
||||
"index": "apps/rxjs-catch-error/src/index.html",
|
||||
"main": "apps/rxjs-catch-error/src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"tsConfig": "apps/rxjs-catch-error/tsconfig.app.json",
|
||||
"assets": [
|
||||
"apps/rxjs-catch-error/src/favicon.ico",
|
||||
"apps/rxjs-catch-error/src/assets"
|
||||
],
|
||||
"styles": ["apps/rxjs-catch-error/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-catch-error:build:production"
|
||||
},
|
||||
"development": {
|
||||
"browserTarget": "rxjs-catch-error:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development"
|
||||
},
|
||||
"extract-i18n": {
|
||||
"executor": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "rxjs-catch-error:build"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"apps/rxjs-catch-error/**/*.ts",
|
||||
"apps/rxjs-catch-error/**/*.html"
|
||||
]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "apps/rxjs-catch-error/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"ci": true,
|
||||
"codeCoverage": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
apps/rxjs-catch-error/src/app/app.component.css
Normal file
32
apps/rxjs-catch-error/src/app/app.component.css
Normal file
@@ -0,0 +1,32 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
.form-container {
|
||||
text-align: center;
|
||||
}
|
||||
input {
|
||||
padding: 8px;
|
||||
margin-right: 8px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
button {
|
||||
padding: 8px 16px;
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.response {
|
||||
margin-left: 25%;
|
||||
margin-top: 2%;
|
||||
width: 50%;
|
||||
text-align: center;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
8
apps/rxjs-catch-error/src/app/app.component.spec.ts
Normal file
8
apps/rxjs-catch-error/src/app/app.component.spec.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { render } from '@testing-library/angular';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
test('...', async () => {
|
||||
await render(AppComponent);
|
||||
});
|
||||
});
|
||||
59
apps/rxjs-catch-error/src/app/app.component.ts
Normal file
59
apps/rxjs-catch-error/src/app/app.component.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { Component, DestroyRef, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { Subject, concatMap, map } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [CommonModule, FormsModule],
|
||||
selector: 'app-root',
|
||||
template: `
|
||||
<div class="form-container">
|
||||
<span
|
||||
>possible values: posts, comments, albums, photos, todos, users</span
|
||||
>
|
||||
</div>
|
||||
<form class="form-container" (ngSubmit)="submit$$.next()">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter text"
|
||||
[(ngModel)]="input"
|
||||
name="action" />
|
||||
<button>Fetch</button>
|
||||
</form>
|
||||
<div class="response">
|
||||
{{ response | json }}
|
||||
</div>
|
||||
`,
|
||||
styleUrls: ['./app.component.css'],
|
||||
})
|
||||
export class AppComponent {
|
||||
submit$$ = new Subject<void>();
|
||||
input = '';
|
||||
response: unknown;
|
||||
private destroyRef = inject(DestroyRef);
|
||||
constructor(private http: HttpClient) {}
|
||||
ngOnInit() {
|
||||
this.submit$$
|
||||
.pipe(
|
||||
map(() => this.input),
|
||||
concatMap((value) =>
|
||||
this.http.get(`https://jsonplaceholder.typicode.com/${value}/1`)
|
||||
),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
)
|
||||
.subscribe({
|
||||
next: (value) => {
|
||||
console.log(value);
|
||||
this.response = value;
|
||||
},
|
||||
error: (error) => {
|
||||
console.log(error);
|
||||
this.response = error;
|
||||
},
|
||||
complete: () => console.log('done'),
|
||||
});
|
||||
}
|
||||
}
|
||||
6
apps/rxjs-catch-error/src/app/app.config.ts
Normal file
6
apps/rxjs-catch-error/src/app/app.config.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [importProvidersFrom(HttpClientModule)],
|
||||
};
|
||||
0
apps/rxjs-catch-error/src/assets/.gitkeep
Normal file
0
apps/rxjs-catch-error/src/assets/.gitkeep
Normal file
BIN
apps/rxjs-catch-error/src/favicon.ico
Normal file
BIN
apps/rxjs-catch-error/src/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
13
apps/rxjs-catch-error/src/index.html
Normal file
13
apps/rxjs-catch-error/src/index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>rxjs-catch-error</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>
|
||||
7
apps/rxjs-catch-error/src/main.ts
Normal file
7
apps/rxjs-catch-error/src/main.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { AppComponent } from './app/app.component';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig).catch((err) =>
|
||||
console.error(err)
|
||||
);
|
||||
5
apps/rxjs-catch-error/src/styles.scss
Normal file
5
apps/rxjs-catch-error/src/styles.scss
Normal file
@@ -0,0 +1,5 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
2
apps/rxjs-catch-error/src/test-setup.ts
Normal file
2
apps/rxjs-catch-error/src/test-setup.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
import '@testing-library/jest-dom';
|
||||
import 'jest-preset-angular/setup-jest';
|
||||
14
apps/rxjs-catch-error/tailwind.config.js
Normal file
14
apps/rxjs-catch-error/tailwind.config.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { createGlobPatternsForDependencies } = require('@nx/angular/tailwind');
|
||||
const { join } = require('path');
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
join(__dirname, 'src/**/!(*.stories|*.spec).{ts,html}'),
|
||||
...createGlobPatternsForDependencies(__dirname),
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
10
apps/rxjs-catch-error/tsconfig.app.json
Normal file
10
apps/rxjs-catch-error/tsconfig.app.json
Normal 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", "src/**/*.test.ts", "src/**/*.spec.ts"]
|
||||
}
|
||||
7
apps/rxjs-catch-error/tsconfig.editor.json
Normal file
7
apps/rxjs-catch-error/tsconfig.editor.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src/**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"types": ["jest", "node"]
|
||||
}
|
||||
}
|
||||
32
apps/rxjs-catch-error/tsconfig.json
Normal file
32
apps/rxjs-catch-error/tsconfig.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"useDefineForClassFields": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.editor.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true
|
||||
}
|
||||
}
|
||||
15
apps/rxjs-catch-error/tsconfig.spec.json
Normal file
15
apps/rxjs-catch-error/tsconfig.spec.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node", "@testing-library/jest-dom"]
|
||||
},
|
||||
"files": ["src/test-setup.ts"],
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"total": 37,
|
||||
"🟢": 13,
|
||||
"total": 38,
|
||||
"🟢": 14,
|
||||
"🟠": 117,
|
||||
"🔴": 207
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ challengeNumber: 37
|
||||
command: performance-ngfor-biglist
|
||||
sidebar:
|
||||
order: 117
|
||||
badge: New
|
||||
---
|
||||
|
||||
## Information
|
||||
|
||||
34
docs/src/content/docs/challenges/rxjs/38-rxjs-catch-error.md
Normal file
34
docs/src/content/docs/challenges/rxjs/38-rxjs-catch-error.md
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: 🟢 catchError
|
||||
description: Challenge 38 is about learning obervable completion.
|
||||
Author: Devesh Chaudhari
|
||||
command: rxjs-catch-error
|
||||
challengeNumber: 38
|
||||
sidebar:
|
||||
order: 14
|
||||
badge: New
|
||||
---
|
||||
|
||||
## Information
|
||||
|
||||
### How to Use the Application
|
||||
|
||||
Our application features a form with a text input box and a "Fetch" button. Upon clicking the "Fetch" button, data is retrieved from a [free API](https://jsonplaceholder.typicode.com/){:target="\_blank"}.
|
||||
|
||||
The correct values for a successful response are limited to: posts, comments, albums, photos, todos, and users. Any other values will result in an error response.
|
||||
|
||||
### Bug
|
||||
|
||||
A bug has been identified in our application. Users are only able to successfully fetch data until an invalid request is sent. Once an error response is received, users are unable to send additional requests.
|
||||
|
||||
### Learnings
|
||||
|
||||
This application provides an opportunity to understand the correct placement of a [`catchError`](https://rxjs.dev/api/operators/catchError) operator. If placed incorrectly, the overall subscription will be completed, preventing users from sending more requests. The goal is to preserve the overall subscription by handling error notifications from inner observables appropriately.
|
||||
|
||||
## Statement
|
||||
|
||||
The goal is to use the catchError operator to handle error management inside your Rxjs stream.
|
||||
|
||||
## Constraints
|
||||
|
||||
Users should be able to log the value/error each time they click the "Fetch" button.
|
||||
@@ -24,8 +24,8 @@ hero:
|
||||
import { Card, CardGrid } from '@astrojs/starlight/components';
|
||||
|
||||
<CardGrid>
|
||||
<Card title="37 Challenges">
|
||||
This repository gathers 37 Challenges related to <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> and <b>Typescript</b>.
|
||||
<Card title="38 Challenges">
|
||||
This repository gathers 38 Challenges related to <b>Angular</b>, <b>Nx</b>, <b>RxJS</b>, <b>Ngrx</b> and <b>Typescript</b>.
|
||||
These challenges resolve around real-life issues or specific features to elevate your skills.
|
||||
</Card>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user