feat: challage 38 - rxjs catch error

This commit is contained in:
Devesh
2023-10-14 01:24:27 +05:30
parent dc9f47e01b
commit ccb3b106dc
23 changed files with 412 additions and 6 deletions

View File

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

View 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": {}
}
]
}

View 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/).

View 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',
],
};

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

View File

@@ -0,0 +1,8 @@
import { render } from '@testing-library/angular';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
test('...', async () => {
await render(AppComponent);
});
});

View File

@@ -0,0 +1,79 @@
import { Component, ElementRef, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { concatMap, fromEvent, map } from 'rxjs';
import { CommonModule } from '@angular/common';
@Component({
standalone: true,
imports: [CommonModule],
selector: 'app-root',
template: `
<div class="form-container">
<span>Posible values: posts, comments, albums, photos, todos, users</span>
</div>
<div class="form-container">
<input #inputRef type="text" placeholder="Enter text" />
<button #buttonRef>Fetch</button>
</div>
<div class="form-container">
{{ response | json }}
</div>
`,
styles: [
`
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;
}
`,
],
})
export class AppComponent {
@ViewChild('buttonRef', { static: true }) buttonRef!: ElementRef;
@ViewChild('inputRef', { static: true }) inputRef!: ElementRef;
response: unknown;
constructor(private http: HttpClient) {}
ngOnInit() {
const buttonClick$ = fromEvent(this.buttonRef.nativeElement, 'click');
buttonClick$
.pipe(
map(() => this.inputRef.nativeElement.value),
concatMap((value) =>
this.http.get(`https://jsonplaceholder.typicode.com/${value}/1`)
)
)
.subscribe({
next: (value) => {
console.log(value);
this.response = value;
},
error: (error) => {
console.log(error);
this.response = error;
},
complete: () => console.log('done'),
});
}
}

View File

@@ -0,0 +1,6 @@
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [importProvidersFrom(HttpClientModule)],
};

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

View 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)
);

View 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 */

View File

@@ -0,0 +1,2 @@
import '@testing-library/jest-dom';
import 'jest-preset-angular/setup-jest';

View 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: [],
};

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", "src/**/*.test.ts", "src/**/*.spec.ts"]
}

View File

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

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

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

View File

@@ -1,6 +1,6 @@
{
"total": 37,
"🟢": 13,
"total": 38,
"🟢": 14,
"🟠": 117,
"🔴": 207
}

View File

@@ -3,7 +3,6 @@ title: 🟠 Optimize Big List
description: Challenge 37 is about learning how virtualization optimize big list rendering
sidebar:
order: 117
badge: New
---
<div class="chip">Challenge #37</div>

View File

@@ -0,0 +1,43 @@
---
title: 🟢 catchError
description: Challenge 38 is about learning error handling with catchError rxjs operator
sidebar:
order: 14
badge: New
---
<div class="chip">Challenge #38</div>
## Information
In this application, we will learn the correct placement of a catchError operator. If wrongly placed, the overall subscription will get completed. And we will not be able to send more requests. Aim is to preserve overall subscription, by taking care of error notification from inner observables.
Possible correct values for which we should get a success response are posts, comments, albums, photos, todos, users
## Statement
Handle the error without completion of the subscription.
## Constraints
## Users should be able to console log value/error each time clicks on the fetch button.
:::note
Start the project by running: `npx nx serve rxjs-catch-error`.
:::
:::tip[Reminder]
Your PR title must start with <b>Answer:38</b>.
:::
<div class="article-footer">
<a
href="https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A38+label%3Aanswer"
alt="catchError community solutions">
❖ Community Answers
</a>
<a
href='https://github.com/tomalaforge/angular-challenges/pulls?q=label%3A38+label%3A"answer+author"'
alt="catchError solution author">
▶︎ Author Answer
</a>
</div>

View File

@@ -23,8 +23,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>