{"id":13553955,"url":"https://github.com/lubkoKuzenko/angular-clean-code","last_synced_at":"2025-04-03T06:30:40.911Z","repository":{"id":40389996,"uuid":"314186076","full_name":"lubkoKuzenko/angular-clean-code","owner":"lubkoKuzenko","description":"My personal best practices when I'm working with Angular.","archived":false,"fork":false,"pushed_at":"2023-05-23T10:29:41.000Z","size":1881,"stargazers_count":332,"open_issues_count":0,"forks_count":67,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-11-04T01:33:02.732Z","etag":null,"topics":["angular","angular-architecture","angular-best-practices","angular-dynamic-components","angular-features","angular-forms","angular-routing","best-practices","clean-code","directives","pipe"],"latest_commit_sha":null,"homepage":"https://lubkokuzenko.github.io/angular-clean-code/","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lubkoKuzenko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2020-11-19T08:41:20.000Z","updated_at":"2024-10-30T20:53:03.000Z","dependencies_parsed_at":"2024-04-07T23:43:49.278Z","dependency_job_id":null,"html_url":"https://github.com/lubkoKuzenko/angular-clean-code","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubkoKuzenko%2Fangular-clean-code","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubkoKuzenko%2Fangular-clean-code/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubkoKuzenko%2Fangular-clean-code/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lubkoKuzenko%2Fangular-clean-code/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lubkoKuzenko","download_url":"https://codeload.github.com/lubkoKuzenko/angular-clean-code/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246947742,"owners_count":20859308,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","angular-architecture","angular-best-practices","angular-dynamic-components","angular-features","angular-forms","angular-routing","best-practices","clean-code","directives","pipe"],"created_at":"2024-08-01T12:02:36.738Z","updated_at":"2025-04-03T06:30:40.887Z","avatar_url":"https://github.com/lubkoKuzenko.png","language":null,"readme":"# Angular Clean Code\n\n\u003cimg src=\"./assets/the-seo-guide-to-angular.png\" width=\"960\"\u003e\n\n## Table of Content\n\n- [Introduction](#Introduction)\n- [Repo](#Repo)\n- [Configuration](#Configuration)\n  - [Configuring tsconfig.json](#Configuring-tsconfigjson)\n  - [Configuring Angular ESLint](#Configuring-Angular-ESLint)\n  - [Configuring stylelint](#Configuring-stylelint)\n  - [Configuring Prettier](#Configuring-Prettier)\n  - [Configuring Proxy for API Calls](#configuring-proxy-for-api-calls)\n  - [Configuring Karma for CI/CD (bamboo example)](#karma-configuration-for-cicd-bamboo-example)\n  - [Configuring Karma for CI/CD (azure example)](#karma-configuration-for-cicd-azure-example)\n- [Architectural principles](#Architectural-principles)\n  - [SOLID](#solid)\n    - [Single responsibility](#single-responsibility)\n    - [Open closed](#open-closed)\n    - [Liskov substitution](#oiskov-substitution)\n    - [Interface segregation](#interface-segregation)\n    - [Dependency Inversion](#dependency-Inversion)\n  - [Don't repeat yourself (DRY)](#code#dont-repeat-yourself-dry)\n  - [Keep it short and simple (KISS)](#keep-it-short-and-simple-kiss-principle)\n- [Angular Architecture](#angular-architecture)\n  - [Project structure](#project-structure)\n    - [AppModule](#AppModule)\n    - [CoreModule](#CoreModule)\n    - [SharedModule](#SharedModule)\n    - [The Feature Modules](#The-Feature-Modules)\n      - [Container Components](#Container-Components)\n      - [Presentational Components](#Presentational-Components)\n      - [Page Components](#Page-Components)\n  - [Data flow architecture](#data-flow-architecture)\n- [Mock API with miragejs](#mock-api-with-miragejs)\n- [Change Detection](#Change-Detection)\n- [State management](#state-management)\n  - [Facade Design Pattern](#facade-design-pattern)\n  - [@ngrx/component-store](#ngrxcomponent-store)\n- [Angular Features](#Angular-Features)\n  - [Component life cycles](#Component-life-cycles)\n  - [Attribute Directive](#Attribute-Directive)\n  - [Structural Directives](#Structural-Directives)\n  - [Pipe](#Pipe)\n  - [NgTemplateOutlet](#NgTemplateOutlet)\n  - [ngClass](#ngClass)\n  - [\\*ngFor](#ngfortrackby)\n- [Angular Forms](#angular-forms)\n  - [Basic setup](#Basic-setup)\n  - [Nested Forms](#Nested-Forms)\n  - [Dynamic Forms](#Dynamic-Forms)\n  - [Custom FormGroup Validator](#Custom-FormGroup-Validator)\n  - [Custom FormControl Validator](#Custom-FormControl-Validator)\n  - [ControlValueAccessor](#ControlValueAccessor)\n  - [Testing Forms](#Testing-Forms)\n- [Angular Routing](#angular-routing)\n  - [Componentless Route](#Componentless-Route)\n  - [Route Resolvers](#Route-Resolvers)\n  - [Custom RouteReuseStrategy](#Custom-RouteReuseStrategy)\n- [Unit testing](#Unit-testing)\n  - [How to test OnPush components](#how-to-test-onpush-components)\n  - [How to test Custom Form Control Validator](#how-to-test-Custom-Form-Control-Validator)\n  - [How to test Pipes](#how-to-test-Pipes)\n  - [How to test Presentational components](#how-to-test-Presentational-components)\n  - [How to test HTTP service](#how-to-test-HTTP-service)\n- [Error Handling](#Error-Handling)\n  - [Errors, Exceptions \u0026 CallStack](#errors-exceptions--callstack)\n  - [Global Error Handler](#Global-Error-Handler)\n- [JWT Token Interceptor](#JWT-Token-Interceptor)\n- [Angular Dynamic Components](#Angular-Dynamic-Components)\n- [Dynamic Importing 3rd-party Libraries](#dynamic-importing-3rd-party-libraries)\n- [Unsubscribe from Observables](#Unsubscribe-from-Observables)\n- [Containerizing Angular using Docker](#Containerizing-Angular-using-Docker)\n- [Angular Schematics](#Angular-Schematics)\n- [Performance](#Performance)\n  - [Webpack Bundle Analyzer](#Webpack-Bundle-Analyzer)\n\n## Introduction\n\nIn order to maintain high quality of delivery and prevent technical debt from being created, we had to agree to a series of guidelines and good practices of how to plan, structure and write applications in Angular\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Repo\n\nRepo with Code: https://github.com/lubkoKuzenko/ng-start\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Configuration\n\n**Resources**\n\n- [\"TypeScript Deep Dive: tsconfig.json\"](https://basarat.gitbook.io/typescript/project/compilation-context/tsconfig)\n\n- [\"tsconfig.json с комментариями\"](https://gist.github.com/lubkoKuzenko/b0dfc526a8be2a00f007542960206260)\n\n- [\"Angular ESLint\"](https://github.com/angular-eslint/angular-eslint#migrating-from-codelyzer-and-tslint/)\n\n- [\"Configuring stylelint\"](https://github.com/stylelint/stylelint/)\n\n- [\"List of stylelint rules\"](https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules/list.md/)\n\n- [\"Prettier Options\"](https://prettier.io/docs/en/options.html/)\n\n- [\"Configure a proxy for your API calls with Angular CLI\"](https://juristr.com/blog/2016/11/configure-proxy-api-angular-cli/)\n\n- [\"Setup a Proxy for API Calls for Your Angular CLI App\"](https://medium.com/better-programming/setup-a-proxy-for-api-calls-for-your-angular-cli-app-6566c02a8c4d/)\n\n### Configuring tsconfig.json\n\nThe presence of a tsconfig.json file in a directory indicates that the directory is the root of a TypeScript project. The tsconfig.json file specifies the root files and the compiler options required to compile the project.\n\n```ts\n// tsconfig.json\n{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    // Basic Options\n    \"target\": \"es5\",                        // Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'.\n    \"module\": \"commonjs\",                  // Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'.\n    \"lib\": [],                             // Specify library files to be included in the compilation:\n    \"allowJs\": true,                       // Allow JavaScript files to be compiled.\n    \"checkJs\": true,                       // Report errors in .js files.\n    \"jsx\": \"preserve\",                     // Specify JSX code generation: 'preserve', 'react-native', or 'react'.\n    \"declaration\": true,                   // Generates corresponding '.d.ts' file.\n    \"sourceMap\": true,                     // Generates corresponding '.map' file.\n    \"outFile\": \"./\",                       // Concatenate and emit output to single file.\n    \"outDir\": \"./\",                        // Redirect output structure to the directory.\n    \"rootDir\": \"./\",                       // Specify the root directory of input files. Use to control the output directory structure with --outDir.\n    \"removeComments\": true,                // Do not emit comments to output.\n    \"noEmit\": true,                        // Do not emit outputs.\n    \"importHelpers\": true,                 // Import emit helpers from 'tslib'.\n    \"downlevelIteration\": true,            // Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'.\n    \"isolatedModules\": true,               // Transpile each file as a separate module (similar to 'ts.transpileModule').\n​\n    // Strict Type-Checking Options\n    \"strict\": true,                        // Enable all strict type-checking options.\n    \"noImplicitAny\": true,                 // Raise error on expressions and declarations with an implied 'any' type.\n    \"strictNullChecks\": true,              // Enable strict null checks.\n    \"noImplicitThis\": true,                // Raise error on 'this' expressions with an implied 'any' type.\n    \"alwaysStrict\": true,                  // Parse in strict mode and emit \"use strict\" for each source file.\n​\n    // Additional Checks\n    \"noUnusedLocals\": true,                // Report errors on unused locals.\n    \"noUnusedParameters\": true,            // Report errors on unused parameters.\n    \"noImplicitReturns\": true,             // Report error when not all code paths in function return a value.\n    \"noFallthroughCasesInSwitch\": true,    // Report errors for fallthrough cases in switch statement.\n​\n    // Module Resolution Options\n    \"moduleResolution\": \"node\",            // Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).\n    \"baseUrl\": \"./\",                       // Base directory to resolve non-absolute module names.\n    \"paths\": {},                           // A series of entries which re-map imports to lookup locations relative to the 'baseUrl'.\n    \"rootDirs\": [],                        // List of root folders whose combined content represents the structure of the project at runtime.\n    \"typeRoots\": [],                       // List of folders to include type definitions from.\n    \"types\": [],                           // Type declaration files to be included in compilation.\n    \"allowSyntheticDefaultImports\": true,  // Allow default imports from modules with no default export. This does not affect code emit, just typechecking.\n​\n    // Source Map Options\n    \"sourceRoot\": \"./\",                    // Specify the location where debugger should locate TypeScript files instead of source locations.\n    \"mapRoot\": \"./\",                       // Specify the location where debugger should locate map files instead of generated locations.\n    \"inlineSourceMap\": true,               // Emit a single file with source maps instead of having a separate file.\n    \"inlineSources\": true,                 // Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set.\n​\n    // Experimental Options\n    \"experimentalDecorators\": true,        // Enables experimental support for ES7 decorators.\n    \"emitDecoratorMetadata\": true          // Enables experimental support for emitting type metadata for decorators.\n  }\n}\n```\n\n### Configuring Angular ESLint\n\nCreate file `.eslintrc` in root folder\n\n```ts\n{\n  \"env\": {\n    \"browser\": true,\n    \"es6\": true,\n    \"node\": true\n  },\n  \"extends\": [\"prettier\", \"prettier/@typescript-eslint\"],\n  \"parser\": \"@typescript-eslint/parser\",\n  \"parserOptions\": {\n    \"project\": \"tsconfig.json\",\n    \"sourceType\": \"module\"\n  },\n  \"plugins\": [\n    \"eslint-plugin-import\",\n    \"@angular-eslint/eslint-plugin\",\n    \"@typescript-eslint\",\n    \"@typescript-eslint/tslint\"\n  ],\n  \"rules\": {\n    \"@angular-eslint/directive-selector\": [\"error\", { \"type\": \"attribute\", \"prefix\": \"bb\", \"style\": \"camelCase\" }],\n    \"@angular-eslint/component-selector\": [\"error\", { \"type\": \"element\", \"prefix\": \"bb\", \"style\": \"kebab-case\" }],\n    \"@angular-eslint/component-class-suffix\": \"error\",\n    \"@angular-eslint/directive-class-suffix\": \"error\",\n    \"@angular-eslint/no-input-rename\": \"error\",\n    \"@angular-eslint/no-output-on-prefix\": \"error\",\n    \"@angular-eslint/no-output-rename\": \"error\",\n    \"@angular-eslint/use-pipe-transform-interface\": \"error\",\n    \"@typescript-eslint/consistent-type-definitions\": \"error\",\n    \"@typescript-eslint/dot-notation\": \"off\",\n    \"@typescript-eslint/explicit-member-accessibility\": [\n      \"off\",\n      {\n        \"accessibility\": \"explicit\"\n      }\n    ],\n    \"@typescript-eslint/member-ordering\": \"error\",\n    \"@typescript-eslint/naming-convention\": \"error\",\n    \"@typescript-eslint/no-empty-function\": \"off\",\n    \"@typescript-eslint/no-empty-interface\": \"error\",\n    \"@typescript-eslint/no-inferrable-types\": [\n      \"error\",\n      {\n        \"ignoreParameters\": true\n      }\n    ],\n    \"@typescript-eslint/no-misused-new\": \"error\",\n    \"@typescript-eslint/no-non-null-assertion\": \"error\",\n    \"@typescript-eslint/no-unused-expressions\": \"error\",\n    \"@typescript-eslint/prefer-function-type\": \"error\",\n    \"@typescript-eslint/quotes\": [\"error\", \"double\"],\n    \"@typescript-eslint/tslint/config\": [\n      \"error\",\n      {\n        \"rules\": {\n          \"whitespace\": true\n        }\n      }\n    ],\n    \"@typescript-eslint/unified-signatures\": \"error\",\n    \"arrow-body-style\": \"error\",\n    \"constructor-super\": \"error\",\n    \"eqeqeq\": [\"error\", \"smart\"],\n    \"guard-for-in\": \"error\",\n    \"id-blacklist\": \"off\",\n    \"id-match\": \"off\",\n    \"import/no-deprecated\": \"warn\",\n    \"no-bitwise\": \"error\",\n    \"no-caller\": \"error\",\n    \"no-console\": [\n      \"error\",\n      {\n        \"allow\": [\n          \"log\",\n          \"dirxml\",\n          \"warn\",\n          \"error\",\n          \"dir\",\n          \"timeLog\",\n          \"assert\",\n          \"clear\",\n          \"count\",\n          \"countReset\",\n          \"group\",\n          \"groupCollapsed\",\n          \"groupEnd\",\n          \"table\",\n          \"Console\",\n          \"markTimeline\",\n          \"profile\",\n          \"profileEnd\",\n          \"timeline\",\n          \"timelineEnd\",\n          \"timeStamp\",\n          \"context\"\n        ]\n      }\n    ],\n    \"no-debugger\": \"error\",\n    \"no-empty\": \"off\",\n    \"no-eval\": \"error\",\n    \"no-fallthrough\": \"error\",\n    \"no-new-wrappers\": \"error\",\n    \"no-restricted-imports\": [\n      \"error\",\n      {\n        \"paths\": [\"rxjs/Rx\"],\n        \"patterns\": [\"rxjs/(?!operators|testing)\"]\n      }\n    ],\n    \"no-shadow\": [\n      \"error\",\n      {\n        \"hoist\": \"all\"\n      }\n    ],\n    \"no-throw-literal\": \"error\",\n    \"no-undef-init\": \"error\",\n    \"no-underscore-dangle\": \"off\",\n    \"no-unused-labels\": \"error\",\n    \"no-var\": \"error\",\n    \"prefer-const\": \"error\",\n    \"radix\": \"error\",\n    \"spaced-comment\": [\n      \"error\",\n      \"always\",\n      {\n        \"markers\": [\"/\"]\n      }\n    ],\n    \"indent\": \"off\"\n  }\n}\n```\n\nAdd command to script section of `package.json`\n\n```ts\n \"lint:ts\": \"eslint --color -c .eslintrc --ext .ts .\",\n```\n\n### Configuring stylelint\n\n1. Install stylelint\n\n```npm\nnpm install --save-dev stylelint stylelint-config-standard\n```\n\n2. Create a .stylelintrc configuration file in the root of your project:\n\n```.stylelintrc\n{\n  \"extends\": \"stylelint-config-standard\"\n}\n```\n\n3. Run stylelint on, for example, all the HTML files in your project:\n\n```npm\n \"lint:scss\": \"npx stylelint \\\"src/**/*.scss\\\" --syntax scss\",\n```\n\n4. Configure rules based on rules list: https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules/list.md\n\n### Configuring Prettier\n\n```ts\n// .prettierrc\nprintWidth: 120\ntabWidth: 2\nsemi: true\nsingleQuote: false\ntrailingComma: all # other options `es5` or `all`\nbracketSpacing: true\narrowParens: always # other option \"always\"\nhtmlWhitespaceSensitivity: 'ignore'\n```\n\n### Configuring Proxy for API Calls\n\nWhen we develop an Angular app which needs a back end to persist data, the back end is often served on another port of localhost. For example, the URL to the front end Angular app is `http://localhost:4200`, while the URL to the back end server is `http://localhost:3000`. In this case, if we make an HTTP request from the front end app to the back end server, it is a cross-domain request and we need to do some extra work to make it happen\n\nAngular CLI uses `webpack-dev-server` as the development server. The `webpack-dev-server` makes use of the powerful `http-proxy-middleware` package which allows us to send API requests on the same domain when we have a separate API back end development server\n\n\u003cimg src=\"./assets/ngdevserver-proxy.png\" width=\"100%\" /\u003e\n\n1. Create a file called `proxy.conf.json` next to our project’s `package.json`\n\n2. Add the following contents to the newly created `proxy.conf.json` file:\n\n```json\n{\n  \"/folder/sub-folder/*\": {\n    \"target\": \"http://localhost:1100\",\n    \"secure\": false,\n    \"pathRewrite\": {\n      \"^/folder/sub-folder/\": \"/new-folder/\"\n    },\n    \"changeOrigin\": true,\n    \"logLevel\": \"debug\"\n  }\n}\n```\n\n3. Edit the `package.json` file’s start script to be:\n\n```npm\n\"start\": \"ng serve --proxy-config proxy.conf.json\",\n```\n\n4. Relaunch the `npm start` process to make our changes effective\n\n#### Options:\n\n`/folder/sub-folder/*` - path says: When I see this path inside my angular app I want to do something with it. The \\* character indicates that everything that follows the sub-folder will be included.\n\n`target` - \"http://localhost:1100\" for the path above make target URL the host/source, therefore in the background we will have.\n\n`pathRewrite` - { \"^/folder/sub-folder/\": \"/new-folder/\" }, Now let's say that you want to test your app locally, the url http://localhost:1100/folder/sub-folder/ may contain an invalid path: /folder/sub-folder/. You want to change that path to a correct one which is http://localhost:1100/new-folder/, therefore the pathRewrite will become useful. It will exclude the path in the app(left side) and include the newly written one (right side)\n\n`secure` - represents wether we are using http or https. If https is used in the target attribute then set secure attribute to true otherwise set it to false\n\n`changeOrigin` - option is only necessary if your host target is not the current environment, for example: localhost. If you want to change the host to www.something.com which would be the target in the proxy then set the changeOrigin attribute to \"true\":\n\n`logLevel` - attribute specifies wether the developer wants to display proxying on his terminal/cmd, hence he would use the \"debug\" value as shown in the image\n\n### Karma configuration for CI/CD (bamboo example)\n\n```js\nmodule.exports = function (config) {\n  config.set({\n    basePath: \"\",\n    frameworks: [\"jasmine\", \"@angular-devkit/build-angular\"],\n    plugins: [\n      require(\"karma-jasmine\"),\n      require(\"karma-chrome-launcher\"),\n      require(\"karma-bamboo-reporter\"),\n      require(\"karma-jasmine-html-reporter\"),\n      require(\"karma-coverage-istanbul-reporter\"),\n      require(\"@angular-devkit/build-angular/plugins/karma\"),\n    ],\n    client: {\n      clearContext: false, // leave Jasmine Spec Runner output visible in browser\n    },\n    coverageIstanbulReporter: {\n      dir: require(\"path\").join(__dirname, \"../../coverage/\"),\n      reports: [\"html\", \"lcovonly\", \"clover\"],\n      fixWebpackSourcePaths: true,\n      \"report-config\": {\n        html: {\n          subdir: \"html\",\n        },\n        clover: {\n          subdir: \"clover\",\n        },\n      },\n    },\n    bambooReporter: {\n      filename: \"coverage/mocha.json\",\n    },\n    reporters: [\"progress\", \"kjhtml\", \"bamboo\"],\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    // browsers: [\"Chrome\"], // enable this line locally for testing and debugging\n    browsers: [\"ChromeHeadlessNoSandbox\"],\n    customLaunchers: {\n      ChromeHeadlessNoSandbox: {\n        base: \"ChromeHeadless\",\n        flags: [\"--no-sandbox\"],\n        options: {\n          viewportSize: {\n            width: 1280,\n            height: 1024,\n          },\n        },\n      },\n    },\n    singleRun: false,\n    restartOnFileChange: true,\n  });\n};\n```\n\n### Configuring Karma for CI/CD (azure example)\n\n```ts\nmodule.exports = function (config) {\n  config.set({\n    basePath: \"\",\n    frameworks: [\"jasmine\", \"@angular-devkit/build-angular\"],\n    plugins: [\n      require(\"karma-jasmine\"),\n      require(\"karma-chrome-launcher\"),\n      require(\"karma-trx-reporter\"),\n      require(\"karma-jasmine-html-reporter\"),\n      require(\"karma-coverage-istanbul-reporter\"),\n      require(\"@angular-devkit/build-angular/plugins/karma\"),\n      require(\"karma-spec-reporter\"),\n    ],\n    client: {\n      clearContext: false, // leave Jasmine Spec Runner output visible in browser\n    },\n    coverageIstanbulReporter: {\n      dir: \"test-results/coverage\",\n      reports: [\"html\", \"lcovonly\", \"text-summary\", \"cobertura\"],\n      fixWebpackSourcePaths: true,\n    },\n    reporters: [\"progress\", \"kjhtml\", \"trx\", \"spec\", \"coverage-istanbul\"],\n    port: 9876,\n    colors: true,\n    logLevel: config.LOG_INFO,\n    autoWatch: true,\n    browsers: [\"Chrome\"],\n    customLaunchers: {\n      ChromeDebugging: {\n        base: \"Chrome\",\n        flags: [\"--remote-debugging-port=9222\"],\n      },\n      ChromeHeadlessNoSandbox: {\n        base: \"Chrome\",\n        flags: [\n          \"--no-sandbox\",\n          \"--disable-setuid-sandbox\",\n          \"--headless\",\n          \"--disable-gpu\",\n          \"--remote-debugging-port=9222\",\n        ],\n      },\n    },\n    singleRun: false,\n    trxReporter: {\n      outputFile: \"test-results/test-results.trx\",\n      shortTestName: false,\n    },\n  });\n};\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Architectural principles\n\n### SOLID\n\nIn object-oriented computer programming, `SOLID` is an acronym for five design principles intended to make software designs more understandable, flexible and maintainable.\n\n`S` — Single responsibility principle\n\n`O` — Open closed principle\n\n`L` — Liskov substitution principle\n\n`I` — Interface segregation principle\n\n`D` — Dependency Inversion principle\n\n#### Single responsibility\n\n`A class should have one and only one reason to change, meaning that a class should only have one job.`\n\nFollowing this principle helps to produce more loosely coupled and modular systems, since many kinds of new behavior can be implemented as new classes, rather than by adding additional responsibility to existing classes. Adding new classes is always safer than changing existing classes, since no code yet depends on the new classes.\n\nWhen this principle is applied to application architecture and taken to its logical endpoint, you get microservices. A given microservice should have a single responsibility. If you need to extend the behavior of a system, it's usually better to do it by adding additional microservices, rather than by adding responsibility to an existing one.\n\n#### Open closed\n\n`Objects or entities should be open for extension, but closed for modification.`\n\n`Open for extension` means that we should be able to add new features or components to the application without breaking existing code.\n\n`Closed for modification` means that we should not introduce breaking changes to existing functionality, because that would force you to refactor a lot of existing code\n\n#### Liskov substitution\n\n`Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T.`\n\nSubclass should override the parent class methods in a way that does not break functionality from a client’s point of view.\n\n#### Interface segregation\n\n`A client should never be forced to implement an interface that it doesn’t use or clients shouldn’t be forced to depend on methods they do not use`\n\n#### Dependency Inversion\n\n`Entities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions`\n\n### Don't repeat yourself (DRY)\n\nThe application should avoid specifying behavior related to a particular concept in multiple places as this practice is a frequent source of errors. At some point, a change in requirements will require changing this behavior. It's likely that at least one instance of the behavior will fail to be updated, and the system will behave inconsistently.\n\nRather than duplicating logic, encapsulate it in a programming construct. Make this construct the single authority over this behavior, and have any other part of the application that requires this behavior use the new construct.\n\n### Keep it Short and Simple (KISS Principle)\n\nKeep it simple, stupid (KISS) is a design principle which states that designs and/or systems should be as simple as possible. Wherever possible, complexity should be avoided in a system—as simplicity guarantees the greatest levels of user acceptance and interaction.\n\n## Angular Architecture\n\n**Resources**\n\n- [\"Angular Application Architecture\"](https://bulldogjob.pl/articles/539-scalable-angular-application-architecture)\n- [\"Angular File Structure and Best Practices\"](https://medium.com/@shijin_nath/angular-right-file-structure-and-best-practices-that-help-to-scale-2020-52ce8d967df5)\n- [\"How to define a highly scalable folder structure for your Angular project\"](https://itnext.io/choosing-a-highly-scalable-folder-structure-in-angular-d987de65ec7)\n- [\"Component Communication in Angular\"](https://www.digitalocean.com/community/tutorials/angular-component-communication)\n- [\"Designing Scalable Angular Apps: Pages, Containers and Views\"](https://blog.bitsrc.io/designing-scalable-angular-apps-pages-containers-and-views-ac9cd83afa2d)\n\n### What is a scalable architecture?\n\nFirst of all, what does it mean that GUI application is scalable? GUI always runs as a single, separate application for every user, so there is no \"high number of users\" challenge that is typical for backend applications. Instead, GUI has to deal with the following scalability factors: increasing size of data loaded to the application, growing complexity and size of the project, usually followed by longer loading times.\n\nThere is also a part of the problem that is not visible from the outside, namely how an application scales from the programmer’s point of view. An application with bad, or not scalable architecture, tends to be very hard to develop after some time. Increasing complexity, technical debt and simply code smell, has a direct impact on project estimates, costs and the quality of the overall solution.\n\nGood architecture does not guarantee that above problems will not occur in your application, however, it gives the development team a powerful tool to reduce and even eliminate most of the issues that they might encounter.\n\nIn short, well designed architecture should work equally good for small and big applications, should provide very good user experience regardless of the application’s size and amount of processed data. Additionally, it should provide a set of clear and easy to follow rules for developers in order to sustain the quality of the project. And finally, it should be simple and preferably based on widely accepted design patterns. We want to keep the learning curve of our applications as small as possible.\n\n### Project structure\n\nApplication modules are clearly visible in the file tree, as separate directories. Every module directory contains all files (code, styles, templates etc.) that are related to a given module. A very important element of this approach is isolation of modules. Simply speaking, it means that every module is self-contained and does not refer to files from different modules, so, theoretically, you can delete one of them from the application, and the rest will work without any problems.\n\n\u003cimg src=\"./assets/content_1.png\" width=\"373\" height=\"549\"\u003e\n\nObviously, it’s not possible to strictly follow this rule in the real world. At least some services and components have to be reused across the whole application. Therefore, some parts of application functionality are stored in \"Core\" and \"Shared\" modules. Now our application structure looks like this:\n\n\u003cimg src=\"./assets/imports.png\" width=\"720\" height=\"420\" style=\"background-color: #ffffff; padding: 2rem\"\u003e\n\nAs you can see, there are now three main modules in the project:\n\n#### AppModule\n\nIn Angular, everything is organized in modules, and every application have at least one of them, the app root module. The app module is the entry point of the application, and is the module that Angular uses to bootstrap the application. The setup instructions when creating a new application produces a minimal `AppModule` with a single component. You’ll evolve this module as the application grows.\n\n```ts\nimport { NgModule } from \"@angular/core\";\n\nimport { CoreModule } from \"./core\";\nimport { SharedModule } from \"./shared\";\n\nimport { AppRoutingModule } from \"./app-routing.module\";\nimport { AppComponent } from \"./app.component\";\n\nimport { DashboardModule } from \"./dashboard/dashboard.module\";\n\n@NgModule({\n  declarations: [AppComponent],\n  imports: [\n    CoreModule,\n    SharedModule,\n\n    // features\n    DashboardModule,\n\n    // app\n    AppRoutingModule,\n  ],\n  providers: [],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n```\n\n#### CoreModule\n\nThe `CoreModule` takes on the role of the app root module, but is not the module that gets bootstrapped by Angular at run-time. The common denominator between the files present here is that we only need to load them once, and that is at run-time, which makes them singleton. The module contains root-scoped services, static components like the navbar and footer, interceptors, guard, constants, enums, utils, and universal models. To prevent re-importing the module elsewhere, we should add a module-import-guard in it’s constructor method.\n\n`Core Module` is only going to be imported into our root module, so this module, normally, don’t have really any exports.\n\nStructure of Core module:\n\n```bash\n├── app\n|  ├── core\n|  |  ├── guards\n|  |  |   └── module-import-guard.ts\n|  |  ├── interceptor\n|  |  |   ├── error-interceptor.ts\n|  |  |   └── jwt-interceptor.ts\n|  |  ├── services\n|  |  |   ├── app-init.service.ts\n|  |  |   └── router-reuse.strategy.ts\n|  |  └── core.module.ts\n|  ├── app-routing.module.ts\n|  └── app.module.ts\n├── favicon.ico\n├── index.html\n├── main.ts\n├── styles.scss\n└── test.ts\n```\n\n```ts\nimport { NgModule, Optional, SkipSelf, ErrorHandler } from \"@angular/core\";\nimport { CommonModule } from \"@angular/common\";\nimport { HttpClientModule, HTTP_INTERCEPTORS } from \"@angular/common/http\";\nimport { TokenInterceptor } from \"./interceptor/jwt-interceptor\";\nimport { AppErrorInterceptor } from \"./interceptor/error-interceptor\";\n\nimport { AppInitService } from \"./services/app-init.service\";\nexport function initializerFactory(appConfig: AppInitService) {\n  return (): Promise\u003cany\u003e =\u003e {\n    return appConfig.load();\n  };\n}\n\n@NgModule({\n  imports: [CommonModule, HttpClientModule],\n  providers: [\n    {\n      provide: HTTP_INTERCEPTORS,\n      useClass: TokenInterceptor,\n      multi: true,\n    },\n    {\n      provide: APP_INITIALIZER,\n      useFactory: initializerFactory,\n      deps: [AppInitService],\n      multi: true,\n    },\n    {\n      provide: ErrorHandler,\n      useClass: AppErrorInterceptor,\n    },\n  ],\n  exports: [HttpClientModule],\n})\nexport class CoreModule {\n  constructor(\n    @Optional()\n    @SkipSelf()\n    parentModule: CoreModule\n  ) {\n    if (parentModule) {\n      throw new Error(\"CoreModule is already loaded. Import only in AppModule\");\n    }\n  }\n}\n```\n\n#### SharedModule\n\n`Shared Module` is the one that almost always will have some exports, because otherwise it wouldn’t be shareable, for sure.\n\nUsually a set of components or services that will be reused in other application modules, not applied globally. They can be imported by feature modules.\n\nStructure of `Shared` module:\n\n```bash\n├── app\n|  ├── shared\n|  |  ├── modules\n|  |  |  ├── primeng.module.ts\n|  |  |  ├── material.module.ts.\n|  |  |  └── *.module.ts\n|  |  ├── components\n|  |  |  ├── *.component.ts\n|  |  |  └── components.module.ts\n|  |  ├── directives\n|  |  |  ├── *.directive.ts\n|  |  |  └── directives.module.ts\n|  |  └── pipes\n|  |    ├── *.pipe.ts\n|  |    └── pipes.module.ts\n|  └── shared.module.ts\n├── index.html\n├── main.ts\n├── styles.scss\n└── test.ts\n```\n\n```ts\n// shared.module.ts\nimport { NgModule } from \"@angular/core\";\nimport { CommonModule } from \"@angular/common\";\nimport { FormsModule, ReactiveFormsModule } from \"@angular/forms\";\nimport { BrowserModule } from \"@angular/platform-browser\";\nimport { BrowserAnimationsModule } from \"@angular/platform-browser/animations\";\n\nimport { SharedDirectivesModule } from \"./directives/directives.module\";\nimport { SharedPipesModule } from \"./pipes/pipes.module\";\nimport { SharedComponentsModule } from \"./components/components.module\";\n\nconst SHARED_MODULES = [\n  CommonModule,\n  FormsModule,\n  ReactiveFormsModule,\n\n  SharedDirectivesModule,\n  SharedPipesModule,\n  SharedComponentsModule,\n];\n\n@NgModule({\n  providers: [],\n  declarations: [],\n  imports: [...SHARED_MODULES],\n  exports: [...SHARED_MODULES],\n})\nexport class SharedModule {}\n```\n\ndirectives.module.ts, pipes.module.ts, components.module.ts has the same structure:\n\n```ts\n// components.module.ts\nimport { CommonModule } from \"@angular/common\";\nimport { NgModule, Type } from \"@angular/core\";\nimport { ReactiveFormsModule } from \"@angular/forms\";\n\nexport const SHARED_COMPONENTS: Array\u003cType\u003cany\u003e\u003e = [];\n\n@NgModule({\n  imports: [CommonModule, ReactiveFormsModule],\n  declarations: [...SHARED_COMPONENTS],\n  exports: [...SHARED_COMPONENTS],\n})\nexport class SharedComponentsModule {}\n```\n\nAll remaining modules (so-called feature modules) should be isolated and independent. Such a structure not only allows for clear concerns separation, but is also a convenient starting point for implementing lazy loading functionality, another crucial step in preparing a scalable application architecture.\n\n\u003cimg src=\"./assets/1_22skrCDLM6C3oRTuIecIng.png\" width=\"100%\" /\u003e\n\n#### The Feature Modules\n\n`Feature Module` is normally a standalone and it will be imported just into the root.\n\nThe initial Angular application does only have one single module, which works great for small applications. But as the application grows, you’ll need to consider subdividing it into multiple feature modules, some which can be lazy loaded. These modules should only depend on the SharedModule, and their functionality should be scoped to the module.\n\n`Feature` modules deliver user experience dedicated to a particular application feature like the user- or the administration-part of the app. We’re grouping the components, services, models and other functionality that belongs together. They typically have a top component that acts as the feature root and private, supporting sub-components descend from it. They might be imported by the root AppModule of a small application that lacks routing or need to show some initial content, but can also be lazy loaded with references in the app routing file.\n\nDomain feature modules rarely have providers, but when they do, the lifetime of the provided services should be the same as the lifetime of the module. Beginning with Angular 6.0, the preferred way pf creating a singleton is to set providedIn to root on the service’ @Injectable decorator. This tells Angular to provide the service in the application root. But we can also use this to create a singleton service is to set providedIn to root on the service's @Injectable() decorator. This tells Angular to provide the service in the application root. We can use this in the context of a feature by using the providedIn property on the module instead, resulting in an error when using it elsewhere.\n\nWhen you need the service in other modules as well, it probably belongs in the CoreModule’ service’s declaration instead.\n\nStructure of `Feature` module:\n\n```bash\n├── app\n|  ├── @core\n|  ├── @shared\n|  ├── feature_one\n|  |   ├── components\n|  |   |   ├── component 1\n|  |   |   ├── component 2\n|  |   |   ├── component 3\n|  |   |   └── components.module.ts\n|  |   ├── containers\n|  |   |   ├── container 1\n|  |   |   ├── container 2\n|  |   |   ├── container 3\n|  |   |   └── containers.module.ts\n|  |   ├── page\n|  |   |   ├── page\n|  |   |   └── page.module.ts\n|  |   ├── feature_one-routing.module.ts\n|  |   └── feature_one.module.ts\n|  ├── feature_two\n|  └── feature_three\n├── index.html\n├── main.ts\n├── styles.scss\n└── test.ts\n```\n\nTo give an overview, the Page Component has Container components as children. Then each Container component has Presentational components as children (Pages -\u003e Containers -\u003e Views).\n\n#### Presentational Components\n\nPresentational components are UI components that comprise the visual elements. They are dumb components that accept data from outside and triggers events for actions like button click. These custom components are typically a composition of UI elements, from libraries like `ng-bootstrap` or `Angular Material` created for business functionality.\n\nWe can unit test these View components easily to test the actions and visualization of data since they don’t have any direct dependencies with services or external states.\n\n- are purely user interface and concerned with how things look.\n- are not aware about the business logic, or services.\n- receive data via @Inputs, and emit events via @Output.\n\n#### Container Components\n\nContainer components are the components that bind, Presentational components, services, and state management together to deliver business functionality.\n\nThe Container components use the services to fetch data from backend and bind them to the Presentational components. They also listen to the events coming from Presentational components and update the state of each Presentational components and communicates with the backend.\n\nContainer components are the hub of connecting things, dealing with business logic, delegating the presentation to View components.\n\n- contain all the business logic.\n- pass the data to the Presentational Components, and handle @Output events raised by them.\n- have no UI logic.\n- do have dependencies on other parts of your app, like services, or your state store.\n\n#### Page Components\n\nPage components are the components that define the layout of a page based on URL paths. For instance, you can compose a page component with a header, footer, and an area in the middle. So basically, you can define a Page component for each parent route. Inside each Page component, you can place your Container components. In some instances, you can place Presentational components directly inside the Page components, when the view components don’t need any dynamic behavior.\n\nBy using Page components, it will help the Container components to know less bout the fixed layout of a page and focus more on dynamic component placement based on business logic. It will also help to reduce the depth of Container components to reuse the layout across different routes.\n\n### Data flow architecture\n\nIn modern SPA frameworks, everything is a component. They are the main building blocks for creating and controlling user interfaces. Angular (and other modern frameworks) will organize components in a hierarchical tree, which means that components can have a parent and children. Let’s imagine that our components communicate with each other with no rules. Any one of them would be sending data and firing events to each other and after a while, it would become very messy and we would be lost in the woods of data requests and responses.\n\nWith this kind of organization, we need to assure unidirectional data flow within our parent and child components. The main rule is that actions go up and data flows down. Every component will accept @Input() parameters to receive the data from their parent and be able to send the @Output() event to notify subscribers that something has happened.\n\n\u003cimg src=\"./assets/angular-project-architecture-diagram2.png\" width=\"100%\" style=\"background-color: #ffffff; padding: 2rem\"\u003e\n\nIn our application we've introduced the idea of \"smart\" and \"dummy\" components. The smart components are also called \"Containers\". The idea behind this division is to clearly define the parts of the application that contain some logic, communicate with services and cause side effects (like service calls, state updates etc.). Every such action is implemented only in Containers. On the contrary, \"stupid\" components have very little or no logic at all. All the data they need is passed by @Input parameters. If a component wants to communicate with the outside word, it has to emit an event (via @Output attribute).\n\n\u003cimg src=\"./assets/content_6.png\" width=\"641\" height=\"201\" style=\"background-color: #ffffff; padding: 2rem\"\u003e\n\nSuch architectural approach is intended to keep the number of Containers as small as possible. The more components in the application are \"dummy\", the simpler is the data flow and the easier it is to work with it. Deciding which component should take the role of a Container and which should be just a plain component is not a trivial task and needs to be resolved per particular case. However, usually the first step we take is assuming that a main screen component should be the smart one, as in the example below, when the container is marked with blue color and simple components are gray.\n\nSuch an approach to architecture is not only about readability of code and organized data flow. Dummy component are much easier to test. Their state is entirely induced by the Input they are provided with, they cause no side effect and the result of any component action is visible as a proper event being fired.\n\nWhat is more, such behavior nicely corresponds with performance optimization of Angular’s change detection process. The change detection strategy for dummy components can be set to \"onPush\" which will trigger the change detection process for the component only when the input properties have been modified. It's an easy and very efficient method of optimizing Angular applications.\n\n## Mock API with mirage.js\n\n**Resources**\n\n- [\"Mirage.js\"](https://miragejs.com/)\n\n### Installation\n\nTo add Mirage to your project, run\n\n```npm\nnpm install --save-dev miragejs\n```\n\n### Usage\n\nCreate folder where all mocks will stay. In my case it's `_be-mocks/`. Then inside it we need `index.ts` file with Server definition.\n\n```ts\n// index.ts\nimport { Server } from \"miragejs\";\nimport * as users from \"./users.json\";\n\nexport default () =\u003e {\n  new Server({\n    seeds(server) {\n      server.db.loadData({\n        users: (users as any).default,\n      });\n    },\n    routes() {\n      this.namespace = \"/api\";\n\n      this.get(\"/users\", (schema) =\u003e schema.db.users[0]);\n    },\n  });\n};\n```\n\nAfter server configurations we need to add it to `app.module.ts`\n\n```ts\n// app.module.ts\nimport mockServer from \"./_be-mocks\";\n\nmockServer();\n```\n\nOn service we are able to get data in this way:\n\n```ts\ngetUsers() {\n  return this.http.get(\"/api/users\");\n}\n```\n\nTo Allows importing modules with a ‘.json’ extension add to your tsconfig.json\n\n```ts\n\"resolveJsonModule\": true\n```\n\n## Change Detection\n\n**Resources**\n\n- [\"Change Detection in Angular\"](https://vsavkin.com/change-detection-in-angular-2-4f216b855d4c)\n- [\"Everything you need to know about change detection in Angular\"](https://indepth.dev/posts/1053/everything-you-need-to-know-about-change-detection-in-angular)\n- [\"The Last Guide For Angular Change Detection You'll Ever Need\"](https://www.mokkapps.de/blog/the-last-guide-for-angular-change-detection-you-will-ever-need/)\n\nThis mechanism of syncing the HTML with our data is called `Change Detection`\n\n#### How Change Detection Works\n\n- Developer updates the data model\n- Angular detects the change\n- Change detection checks every component in the component tree from top to bottom to see if the corresponding model has changed\n- If there is a new value, it will update the component’s view (DOM)\n\nBy default, Angular `Change Detection` checks for all components from top to bottom if a template value has changed\n\n#### Change Detection Strategies\n\nAngular provides two strategies to run change detections:\n\n- Default\n  By default, Angular uses the `ChangeDetectionStrategy.Default` change detection strategy. This default strategy checks every component in the component tree from top to bottom every time an event triggers change detection (like user event, timer, XHR, promise and so on). This conservative way of checking without making any assumption on the component’s dependencies is called dirty checking. It can negatively influence your application’s performance in large applications which consists of many components\n\n  \u003cimg src=\"./assets/cd-cycle.gif\" /\u003e\n\n- OnPush\n  We can switch to the `ChangeDetectionStrategy.OnPush` change detection strategy by adding the changeDetection property to the component decorator metadata\n\n  \u003cimg src=\"./assets/0_LHWjj-bxWhxjMYiG.gif\" /\u003e\n\n  The `OnPush` change detection strategy allows us to disable the change detection mechanism for subtrees of the component tree. By setting the change detection strategy to any component to the value `ChangeDetectionStrategy.OnPush` will make the change detection perform **only** when the component has received different inputs. Angular will consider inputs as different when it compares them with the previous inputs by reference, and the result of the reference check is `false`. In combination with [immutable data structures](https://facebook.github.io/immutable-js/), `OnPush` can bring great performance implications for such \"pure\" components.\n\n## State management\n\n**Resources**\n\n- [\"An Angular Architect's First Experiences\"](https://www.thinktecture.com/en/angular/should-i-use-ngrx-an-agular-achitects-experiences/)\n\n### Facade Design Pattern\n\nFacade discusses encapsulating a complex subsystem within a single interface object. This reduces the learning curve necessary to successfully leverage the subsystem. It also promotes decoupling the subsystem from its potentially many clients.\nThe Facade object should be a fairly simple advocate or facilitator. It should not become an all-knowing oracle or “god” object.\nHere is the good read for Facade design pattern in details\n\n\u003cimg src=\"./assets/example-of-facade-designpattern-in-uml.png\" width=\"100%\"\u003e\n\nI would recommend following steps to build Angular services using Facade pattern:\n\n- Define all your Angular services as per your business requirement and/or keep adding more as needed.\n- Create a service called “FacadeService” (feel free to use any other name here)\n- Create a Module and provide all Angular services\n\n```ts\n// user.service.ts\nimport { Injectable } from \"@angular/core\";\n\n@Injectable()\nexport class UserService {\n  constructor() {}\n\n  getUsers() {\n    return [{ name: \"test\" }];\n  }\n}\n```\n\n```ts\n// facade.service.ts\n@Injectable()\nexport class FacadeService {\n  // users\n  public users$ = new BehaviorSubject\u003cUser[]\u003e([]);\n\n  constructor(public userService: UserService) {}\n\n  public getUsers() {\n    return this.users$.next(this.userService.getUsers());\n  }\n}\n```\n\n```ts\n// ./containers/users.component.ts\n@Component({\n  templateUrl: \"./users.html\",\n  styleUrls: [\"./users.scss\"],\n})\nexport class UsersComponent implements OnInit {\n  public users$ = this.facadeService.users$;\n\n  constructor(public facadeService: FacadeService) {}\n\n  public ngOnInit(): void {\n    this.facadeService.getUsers();\n  }\n}\n```\n\n```html\n\u003c!-- ./containers/users.component.html  --\u003e\n{{ users$ | async | json }}\n```\n\n```ts\n// feature.module.ts\n@NgModule({\n  imports: [CommonModule],\n  declarations: [],\n  providers: [UserService, FacadeService],\n})\nexport class FeatureModule {}\n```\n\n### @ngrx/component-store\n\nThe component store is a local, stand-alone, store-like implementation, similar to the \"Subject in a Service\" pattern, offering a standardized store-like API for you.\n\n#### It has only three very simple concepts that you have to learn:\n\n`Selectors`: You select and subscribe to the state, either all or parts of it.\n\n`Updater`: To update the state. It can be parts or in whole.\n\n`Effects`: It is also to update the state but do some other necessary task beforehand. For example, an HTTP request to an API.\n\n#### Adding the @ngrx/component-store\n\n1. `npm install @ngrx/component-store --save`\n2. create `*.store.ts` file in `store` folder\n3. provide store service in component where it will be used `providers: [*Store]`\n4. add dependency to constructor `constructor(private readonly store: *Store) {}`\n5. use available methods `this.store`\n\n#### CRUD Example - https://github.com/lubkoKuzenko/ng-start/tree/master/src/app/unit-cards\n\n```typescript\nimport { Injectable } from \"@angular/core\";\nimport { ComponentStore, tapResponse } from \"@ngrx/component-store\";\nimport { Observable } from \"rxjs\";\nimport { switchMap } from \"rxjs/operators\";\nimport { Card } from \"../interfaces\";\nimport { CardsService } from \"../services/cards.service\";\n\n// The state model\nexport interface CardsState {\n  cards: Card[];\n  loading: boolean;\n}\n\nconst defaultState: CardsState = {\n  cards: [],\n  loading: false,\n};\n\n@Injectable()\nexport class CardsStore extends ComponentStore\u003cCardsState\u003e {\n  constructor(public cardsService: CardsService) {\n    super(defaultState);\n  }\n\n  // SELECTORS\n  readonly cards$: Observable\u003cCard[]\u003e = this.select((state) =\u003e state.cards);\n  readonly loading$: Observable\u003cboolean\u003e = this.select(\n    (state) =\u003e state.loading\n  );\n\n  // EFFECTS\n  public readonly loadCards = this.effect((trigger$: Observable\u003cvoid\u003e) =\u003e\n    trigger$.pipe(\n      switchMap(() =\u003e {\n        this.patchState({ loading: true });\n\n        return this.cardsService.getCards().pipe(\n          tapResponse(\n            (cards) =\u003e\n              this.patchState((state) =\u003e ({\n                ...state,\n                cards: cards || [],\n                loading: false,\n              })),\n            (_) =\u003e this.patchState({ cards: [] })\n          )\n        );\n      })\n    )\n  );\n\n  public readonly addCard = this.effect((trigger$: Observable\u003cCard\u003e) =\u003e\n    trigger$.pipe(\n      switchMap((card: Card) =\u003e {\n        this.patchState({ loading: true });\n\n        return this.cardsService.addCard(card).pipe(\n          tapResponse(\n            (newCard: Card) =\u003e\n              this.patchState((state) =\u003e ({\n                ...state,\n                cards: [...state.cards, newCard],\n                loading: false,\n              })),\n            (_) =\u003e this.patchState((state) =\u003e ({ cards: state.cards }))\n          )\n        );\n      })\n    )\n  );\n\n  public readonly updateCard = this.effect((trigger$: Observable\u003cCard\u003e) =\u003e\n    trigger$.pipe(\n      switchMap((card: Card) =\u003e {\n        this.patchState({ loading: true });\n\n        return this.cardsService.updateCard(card).pipe(\n          tapResponse(\n            () =\u003e\n              this.patchState((state) =\u003e {\n                const updatedCards = state.cards.map((c: Card) =\u003e\n                  c.id === card.id ? { ...c, ...card } : c\n                );\n\n                return {\n                  ...state,\n                  cards: [...updatedCards],\n                  loading: false,\n                };\n              }),\n            (_) =\u003e this.patchState((state) =\u003e ({ cards: state.cards }))\n          )\n        );\n      })\n    )\n  );\n\n  public readonly removeCard = this.effect((trigger$: Observable\u003cstring\u003e) =\u003e\n    trigger$.pipe(\n      switchMap((cardId: string) =\u003e {\n        this.patchState({ loading: true });\n\n        return this.cardsService.deleteCard(cardId).pipe(\n          tapResponse(\n            () =\u003e\n              this.patchState((state) =\u003e {\n                const updatedCards = state.cards.filter(\n                  (card) =\u003e card.id !== cardId\n                );\n\n                return {\n                  ...state,\n                  cards: [...updatedCards],\n                  loading: false,\n                };\n              }),\n            (_) =\u003e this.patchState((state) =\u003e ({ cards: state.cards }))\n          )\n        );\n      })\n    )\n  );\n}\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Angular Features\n\n**Resources**\n\n- [\"How to Use ngTemplateOutlet\"](https://www.tektutorialshub.com/angular/ngtemplateoutlet-in-angular/)\n\n- [\"ngTemplateOutlet: The secret to customisation\"](https://indepth.dev/posts/1405/ngtemplateoutlet/)\n\n- [\"Angular NgClass Example – How to Add Conditional CSS Classes\"](https://www.freecodecamp.org/news/angular-ngclass-example/)\n\n- [\"Writing your own structural directives with context variables\"](https://github.com/JanMalch/ngx-code-dump/tree/master/custom%20directives/)\n\n### Component life cycles\n\n\u003cimg src=\"./assets/lifecycle-hooks.webp\" width=\"100%\" /\u003e\n\n| Life cycle            | Description                                                                      |\n| --------------------- | -------------------------------------------------------------------------------- |\n| ngOnInit              | Called once, after the first ngOnChanges()                                       |\n| ngOnChanges           | Called before ngOnInit() and whenever one of input properties change.            |\n| ngOnDestroy           | Called just before Angular destroys the directive/component                      |\n| ngDoCheck             | Called during every change detection run                                         |\n| ngAfterContentChecked | Called after the ngAfterContentInit() and every subsequent ngDoCheck()           |\n| ngAfterViewChecked    | Called after the ngAfterViewInit() and every subsequent ngAfterContentChecked(). |\n| ngAfterContentInit    | Called once after the first ngDoCheck().                                         |\n| ngAfterViewInit       | Called once after the first ngAfterContentChecked().                             |\n\n### Directives\n\n\u003cimg src=\"./assets/1_OhepgWassGUMkQ6v8VtK3g.png\" width=\"100%\" /\u003e\n\n### Attribute Directive\n\nDirective should be stored in Directives folder of Shared Module.\n\n```ts\n// underline.directive.ts\nimport {\n  Directive,\n  ElementRef,\n  HostListener,\n  HostBinding,\n  Renderer2,\n} from \"@angular/core\";\n\n// Annotation section\n@Directive({ selector: \"[bbUnderline]\" })\n\n/*\n *element-name: select by element name.\n *.class: select by class name.\n *[attribute]: select by attribute name.\n *[attribute=value]: select by attribute name and value.\n *:not(sub_selector): select only if the element does not match the sub_selector.\n *selector1, selector2: select if either selector1 or selector2 matches.\n */\nexport class UnderlineDirective {\n  // @Input() my: boolean;\n  constructor(private el: ElementRef, private renderer: Renderer2) {}\n\n  // HostBinding - will bind property to host element, If a binding changes, HostBinding will update the host element.\n  // @HostBinding('style.backgroundColor')\n  // color = 'yellow';\n\n  // HostListener - will listen to the event emitted by host element, declared with @HostListener.\n  @HostListener(\"mouseenter\")\n  onMouseEnter() {\n    this.hover(true);\n  }\n\n  @HostListener(\"mouseleave\")\n  onMouseLeave() {\n    this.hover(false);\n  }\n\n  hover(shouldUnderline: boolean) {\n    if (shouldUnderline) {\n      this.renderer.setStyle(\n        this.el.nativeElement,\n        \"text-decoration\",\n        \"underline\"\n      );\n    } else {\n      this.renderer.setStyle(this.el.nativeElement, \"text-decoration\", \"none\");\n    }\n  }\n}\n```\n\n### Structural Directives\n\n`Structural Directive` in Angular are responsible for manipulating, modifying and removing elements inside a template of a component. A structural directive is applied on a main element and according to the behavior of structural directive, it modifies and updates the main elements and its child elements. We have some inbuilt structural directives in Angular like `ngFor`, `ngSwitch` and `ngIf`\n\n### Creating a custom structural directive\n\n```ts\n@Directive({\n  selector: \"[delayRendering]\",\n})\nexport class DelayRenderingDirective {\n  constructor(\n    private template: TemplateRef\u003cany\u003e,\n    private container: ViewContainerRef\n  ) {}\n\n  @Input()\n  set delayRendering(delayTime: number): void {}\n\n  // Rendering\n  ngOnInit() {\n    this.createView();\n  }\n\n  private createView() {\n    this.container.clear();\n    this.container.createEmbeddedView(this.template);\n  }\n}\n```\n\n`TemplateRef`: Reference to content enclosed within the container\n`ViewContainerRef`: Refers to the Container to which directive is applied\n\n### Applying Directive to the Element\n\n```html\n\u003cdiv *delayRendering=\"1000\"\u003e\n  \u003ch1\u003eThis is the Template area\u003c/h1\u003e\n\u003c/div\u003e\n```\n\nTo create the default input, you add a @Input() and give it the same name as the directive selector\n\n```ts\n@Input() set delayRendering(delayTime: number): void { }\n```\n\nLets add `test` input you add another @Input(). The name has to start with the directive selector and then the actual variable name, but with the first letter capitalized.\n\n```ts\n@Input() set delayRenderingTest(test: number): void { }\n```\n\n### Using variables in the template\n\nYou cannot use the delayRendering or delayRenderingTest variables in your HTML just yet. To do this you have to provide a context object. A context object can be any plain object literal\n\nFirst define an interface for our directive:\n\n```ts\nexport interface DirectiveContext {\n  $implicit: number;\n  delayRendering: number;\n  delayRenderingTest: number;\n}\n```\n\nThese variables will be availabe in your directive / HTML. To get these values you have to use the `let x = ...` syntax. Where x can be any variable name you want. To connect `x` with the value of delayRendering you would write `let x = delayRendering`. Then you can use your `x` variable in the template like this:\n\n```html\n\u003cdiv *delayRendering=\"10; test: 3; let x = test;\"\u003etestValue = {{ x }}\u003c/div\u003e\n```\n\nThe `$implicit` variable is sugared syntax as you can omit it when connecting to a variable. So `let input = $implicit`; is the same as `let input`. With this we can already get all our variables in the template\n\n```html\n\u003cdiv *delayRendering=\"10; test: 3; let input;\"\u003etestValue = {{ x }}\u003c/div\u003e\n```\n\n### Pipe\n\nA pipe takes in data as input and transforms it to a desired output.\n\n\u003cimg src=\"./assets/147465973-deccba45-bf93-41f0-961a-d5f86bcadb3b.png\" width=\"100%\"\u003e\n\nA `pure pipe` is only called when Angular detects a change in the value or the parameters passed to a pipe. For example, any changes to a primitive input value (String, Number, Boolean, Symbol) or a changed object reference (Date, Array, Function, Object).\n\nAn `impure pipe` is called for every change detection cycle no matter whether the value or parameters changes. i.e, An impure pipe is called often, as often as every keystroke or mouse-move.\n\n#### Built-in Pipes\n\nAngular provides built-in pipes for typical data transformations\n\n| Pipe           | Description                                                                      | Example                                |\n| -------------- | -------------------------------------------------------------------------------- | -------------------------------------- |\n| AsyncPipe      | Used to read the object from an asynchronous source                              | `{{data \\| async}}`                    |\n| CurrencyPipe   | Used to format the currencies                                                    | `{{ 1234.56 \\| currency:'USD' }}`      |\n| DatePipe       | Used to format the dates                                                         | `{{ dateVal \\| date: 'fullDate' }}`    |\n| DecimalPipe    | Used to transform the decimal numbers                                            | `{{ 3.141265 \\| number: '1.4-4' }}`    |\n| I18nPluralPipe | Converts a value to a string that pluralizes the value according to locale rules |\n| I18nSelectPipe | Used to display values according to the selection criteria                       |\n| KeyValuePipe   | Converts an Object or Map into an array of key value pairs                       | `*ngFor=\"let row of rows \\| keyvalue\"` |\n| JsonPipe       | Converts an object into a JSON string                                            | `{{ jsonVal \\| json }}`                |\n| LowerCasePipe  | Converts a string or text to lowercase                                           | `{{ 'TEST' \\| lowercase }}`            |\n| PercentPipe    | Used to display percentage numbers                                               | `{{ 0.1236 \\| percent: '2.1-2' }}`     |\n| SlicePipe      | Used to slice an array                                                           | `{{ [1,2,3,4,5,6] \\| slice:2 }}`       |\n| TitleCasePipe  | Converts a string or text to title case                                          | `{{ 'test' \\| titlecase }}`            |\n| UpperCasePipe  | Converts a string or text to uppercase                                           | `{{ 'test' \\| uppercase }}`            |\n\n#### Custom Pipes\n\nAngular gives us the freedom to create custom pipes to encapsulate transformations that are not provided with the built-in pipes and to use them the same way as the built-in pipes.\n\n```ts\n// reverse.pipe.ts\n// how to use {{text | reverseStr}}\nimport { Pipe, PipeTransform } from \"@angular/core\";\n\n@Pipe({\n  name: \"reverseStr\",\n})\nexport class ReverseStrPipe implements PipeTransform {\n  transform(value: string): string {\n    let newStr = \"\";\n\n    for (let i = value.length - 1; i \u003e= 0; i--) {\n      newStr += value.charAt(i);\n    }\n\n    return newStr;\n  }\n}\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## NgTemplateOutlet\n\n### What is ngTemplateOutlet?\n\n`ngTemplateOutlet` is a structural directive. We use it to insert a template (created by `ngTemplate`) in various sections of our DOM. For example, you can define a few templates to display an item and use them display at several places in the View and also swap that template as per the user’s choice.\n\n### How to use ngTemplateOutlet?\n\nIn the following code, we have a template defined using the `ng-template`. The Template reference variable holds the reference the template.\n\nThe template does not render itself. We must use a structural directive to render it. That is what `ngTemplateOutlet` does\n\nWe pass the Template Reference to the `ngTemplateOutlet` directive. It renders the template.\n\n```html\n\u003cng-template #listTemplate\u003e\n  \u003cspan\u003elist\u003c/span\u003e\n\u003c/ng-template\u003e\n\n\u003c!-- The following code does not render the span --\u003e\n\u003cdiv *ngTemplateOutlet=\"listTemplate\"\u003e\u003c/div\u003e\n```\n\n### Passing data to ngTemplateOutlet\n\nWe can also pass data to the using its second property `ngTemplateOutletContext`\n\nThe following code creates a template. We name it as `listTemplate`. The `let-value` creates a local variable with the name `value`\n\n```html\n\u003cng-template let-value=\"value\" #listTemplate\u003e\n  \u003cp\u003eValue Received from the Parent is {{value}}\u003c/p\u003e\n\u003c/ng-template\u003e\n\n\u003c!-- We can pass any value to the value using the ngTemplateOutletContextproperty --\u003e\n\u003cng-container\n  [ngTemplateOutlet]=\"listTemplate\"\n  [ngTemplateOutletContext]=\"{value:'1000'}\"\n\u003e\n\u003c/ng-container\u003e\n```\n\nIf you use the key `$implicit` in the context object will set its value as default for all the local variables.\n\n```html\n\u003cng-template let-name let-message=\"message\" #listTemplate\u003e\n  \u003cp\u003eDear {{name}} , {{message}}\u003c/p\u003e\n\u003c/ng-template\u003e\n\n\u003cng-container\n  [ngTemplateOutlet]=\"listTemplate\"\n  [ngTemplateOutletContext]=\"{$implicit:'Guest',message:'Welcome to our site'}\"\n\u003e\n\u003c/ng-container\u003e\n```\n\nWe have not assigned anything to the `let-name` so it will take the value from the `$implicit`, which is Guest\n\n### Passing Template to a Child Component\n\nWe can pass the entire template to a child component from the parent component. The technique is similar to passing data from parent to child component\n\n```html\n\u003cng-template #parentTemplate\u003e\n  \u003cp\u003eThis Template is defined in Parent.\u003c/p\u003e\n\u003c/ng-template\u003e\n\n\u003cchild [customTemplate]=\"parentTemplate\"\u003e\u003c/child\u003e\n```\n\nIn the Child, component receive the `parentTemplate` using the `@Input`(). And then pass it to `ngTemplateOutlet`\n\n```ts\n@Input() customTemplate: TemplateRef\u003cHTMLElement\u003e;\n```\n\nUse the `ViewChild` to get the access to the `parentTemplate` in the component\n\n```ts\n@ViewChild(\"listTemplate\", { static: false }) listTemplate: TemplateRef\u003cHTMLElement\u003e;\n\npublic get template() {\n  return this.isCard ? this.cardTemplate : this.listTemplate;\n}\n```\n\n```html\n\u003cusers-view [userTemplate]=\"template\"\u003e\u003c/users-view\u003e\n```\n\n## ngClass\n\n`ngClass` is a directive in Angular that adds and removes CSS classes on an HTML element\n\n```html\n\u003c!-- Basic --\u003e\n\u003cdiv [ngClass]=\"'first second'\"\u003e\n  \u003cdiv [ngClass]=\"['first', 'second']\"\u003e\n    \u003cdiv [ngClass]=\"{first: true, second: true, third: true}\"\u003e\n      \u003cdiv [ngClass]=\"{'first second': true}\"\u003e\u003c/div\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n```html\n\u003c!-- Expression --\u003e\n\u003cdiv [ngClass]=\"val + val\"\u003e\n  \u003cdiv [ngClass]=\"[val]\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n\n```html\n\u003c!-- Condition --\u003e\n\u003cspan [ngClass]=\"val \u003e 10 ? 'red' : 'green'\"\u003e{{ val }}\u003c/span\u003e\n\u003cspan [ngClass]=\"{ error: control.isInvalid }\"\u003e\u003c/span\u003e\n\u003cspan [class.error]=\"control.isInvalid\"\u003e\u003c/span\u003e\n```\n\n```ts\n// ngClass as function\nimport { Component } from \"@angular/core\";\n\n@Component({\n  template: '\u003cspan [ngClass]=\"getClassOf(val)\"\u003e{{ val }}\u003c/span\u003e',\n})\nexport class AppComponent {\n  getClassOf(val) {\n    if (val \u003e= 0 \u0026\u0026 val \u003c= 5) {\n      return \"low\";\n    } else if (val \u003e 5 \u0026\u0026 val \u003c= 10) {\n      return \"medium\";\n    } else {\n      return \"high\";\n    }\n  }\n}\n```\n\n```ts\n// ngClass with values in Array\nimport { Component } from \"@angular/core\";\n\ntype Val = 1 | 2 | 3;\n\n@Component({\n  template: '\u003cspan [ngClass]=\"classArr[val - 1]\"\u003e{{ val }}\u003c/span\u003e',\n})\nexport class AppComponent {\n  classArr = [\"first-element\", \"second-element\", \"third-element\"];\n  val: Val = 1;\n}\n```\n\n```ts\n// ngClass with values in Object\nimport { Component } from \"@angular/core\";\n\ntype Val = 1 | 2 | 3;\n\n@Component({\n  template: '\u003cspan [ngClass]=\"classMap[val]\"\u003e{{ val }}\u003c/span\u003e',\n})\nexport class AppComponent {\n  classMap = {\n    1: \"first-element\",\n    2: \"second-element\",\n    3: \"third-element\",\n  };\n  val: Val = 1;\n}\n```\n\n## \\*ngFor:TrackBy\n\n#### Why do we need to use ngFor trackBy in the angular application?\n\n- The trackBy used to improve the performance of the angular project.\n- It is usually not needed only when your application running into performance issues.\n- The angular ngFor directive may perform poorly with large applications.\n- A little change to the collection is adding a new item or removing an existing item from the collection may trigger a cascade of DOM manipulations.\n- Assume, we have some data coming from some back-end API and we are storing data into some type of collection like an array and then we need to update these data over the webpage using ngFor directive.\n- By default, what the angular framework will do is, it will remove all the DOM elements that are associated with the data and will create them again in the DOM tree even if the equal data is coming.\n- A lot of DOM Manipulation will occur in the background if a large amount of data coming from the back-end API repeatedly.\n\n```ts\nimport { Component } from \"@angular/core\";\n\n@Component({\n  selector: \"app-tasks-list\",\n  template: `\n    \u003cul\u003e\n      \u003cli *ngFor=\"let task of tasks; trackBy: identify\"\u003e{{ task.title }}\u003c/li\u003e\n    \u003c/ul\u003e\n  `,\n})\nexport class MoviesListComponent {\n  tasks: any[] = [\n    { id: 1, title: \"Working\" },\n    { id: 2, title: \"Pending\" },\n  ];\n\n  public identify(index: number, task: any) {\n    return task.id; // unique identifier from element\n  }\n}\n```\n\nAlso generic npm package is available\n\nhttps://github.com/nigrosimone/ng-for-track-by-property\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Angular Forms\n\n**Resources**\n\n- [\"Custom Form Validators\"](https://codecraft.tv/courses/angular/advanced-topics/basic-custom-validators/)\n- [\"Custom Form Validation in Angular\"](https://www.digitalocean.com/community/tutorials/angular-custom-validation/)\n\n- [\"Reactive FormGroup validation with AbstractControl in Angular\"](https://ultimatecourses.com/blog/reactive-formgroup-validation-angular-2/)\n\n- [\"ControlValueAccessor in Angular forms\"](https://indepth.dev/posts/1055/never-again-be-confused-when-implementing-controlvalueaccessor-in-angular-forms/)\n\n- [\"Using ControlValueAccessor to Create Custom Form Controls in Angular\"](https://www.digitalocean.com/community/tutorials/angular-custom-form-control/)\n\n- [\"Testing Dynamic Forms in Angular\"](https://www.telerik.com/blogs/testing-dynamic-forms-in-angular/)\n\n### Basic setup\n\n```ts\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  Input,\n  OnInit,\n} from \"@angular/core\";\nimport { FormControl, FormGroup, Validators } from \"@angular/forms\";\n\n@Component({\n  selector: \"lib-form\",\n  templateUrl: \"./form.component.html\",\n  styleUrls: [\"./form.component.scss\"],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class FormGeneralComponent implements OnInit {\n  public form = new FormGroup({\n    name: new FormControl(\"\", [Validators.required]),\n    description: new FormControl(undefined, [Validators.required]),\n    status: new FormControl(1, [Validators.required]),\n  });\n\n  get controls() {\n    return this.form.controls;\n  }\n\n  public ngOnInit() {\n    this.initializeFormValues();\n  }\n\n  // reset form\n  public reset() {\n    this.form.reset();\n  }\n\n  // populate form values\n  public initializeFormValues() {\n    this.form.patchValue({\n      name: \"name\",\n      description: \"description\",\n      status: 2,\n    });\n  }\n\n  // GET form values\n  public onSubmit() {\n    this.form.getRawValue();\n  }\n}\n```\n\n### Nested Forms\n\nThe best approach is to create a stateful parent component and many children stateless components.\n\nParent component needs to be dedicated for particular form. Child components can be reused everywhere many times.\n\n#### Parent component rules:\n\n- stateful\n- creates and holds form definition\n- emits form state (value, valid, pristine) on every form change\n- holds custom validation logic\n\n#### Children components rules:\n\n- stateless\n- receives form parts (nested FormGroups) from parent\n- no custom validation logic\n\nIn above scenario children components are \"reusable views\" without any validation logic. It will always comes from parent.\n\n#### Parent component\n\n```ts\n// parent-form.componnet.ts\nimport { Component, ChangeDetectionStrategy } from \"@angular/core\";\nimport { FormGroup } from \"@angular/forms\";\n\n@Component({\n  selector: \"bb-nested-form\",\n  templateUrl: \"./nested-form.component.html\",\n  styleUrls: [\"./nested-form.component.scss\"],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class NestedFormComponent {\n  public form = new FormGroup({\n    general: new FormGroup({}),\n  });\n\n  get controls() {\n    return this.form.controls;\n  }\n\n  public onSubmit() {\n    if (this.form.valid) {\n      const formValue = this.form.getRawValue();\n      console.log(formValue);\n    }\n  }\n}\n```\n\n```html\n\u003c!-- parent-form.component.html --\u003e\n\u003cdiv class=\"row\"\u003e\n  \u003cdiv class=\"col-6\"\u003e\n    \u003clabel\u003eGeneral:\u003c/label\u003e\n    \u003cbb-form-general [parentForm]=\"controls.general\"\u003e\u003c/bb-form-general\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\n\u003cbutton (click)=\"onSubmit()\"\u003eSubmit form\u003c/button\u003e\n```\n\n#### Child component\n\n```ts\n// child-form.component\nimport {\n  Component,\n  OnInit,\n  Input,\n  ChangeDetectionStrategy,\n} from \"@angular/core\";\nimport { FormGroup, FormControl, Validators } from \"@angular/forms\";\nimport { FormsService } from \"../../../services/forms.service\";\n\n@Component({\n  selector: \"bb-form-general\",\n  templateUrl: \"./form-general.component.html\",\n  styleUrls: [\"./form-general.component.scss\"],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class FormGeneralComponent implements OnInit {\n  @Input() public parentForm!: FormGroup;\n\n  public form = new FormGroup({\n    name: new FormControl(\"\", [Validators.required]),\n    description: new FormControl(undefined, [Validators.required]),\n  });\n\n  get controls() {\n    return this.form.controls;\n  }\n\n  constructor(public formsService: FormsService) {}\n\n  public ngOnInit() {\n    this.formsService.addGroupToParentForm(this.parentForm, this.form);\n  }\n}\n```\n\n```html\n\u003cform [formGroup]=\"form\"\u003e\n  \u003cdiv class=\"row\"\u003e\n    \u003cdiv class=\"col-12\"\u003e\n      \u003clabel\u003eName\u003c/label\u003e\n      \u003cinput type=\"text\" formControlName=\"name\" /\u003e\n    \u003c/div\u003e\n\n    \u003cdiv class=\"col-12\"\u003e\n      \u003clabel\u003eDescription\u003c/label\u003e\n      \u003ctextarea type=\"text\" formControlName=\"description\"\u003e\u003c/textarea\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/form\u003e\n```\n\n#### Form service\n\n```ts\n// forms.service.ts\nimport { Injectable } from \"@angular/core\";\nimport { FormGroup } from \"@angular/forms\";\n\n@Injectable()\nexport class FormsService {\n  public addGroupToParentForm(parentForm: FormGroup, group: FormGroup) {\n    for (const [key, control] of Object.entries(group.controls)) {\n      parentForm.addControl(key, control);\n    }\n    group.setParent(parentForm);\n  }\n}\n```\n\n### Dynamic Forms\n\n```ts\n// dynamic-form.component.ts\nimport { Component } from \"@angular/core\";\nimport { FormGroup, FormArray, FormControl, Validators } from \"@angular/forms\";\n\n@Component({\n  selector: \"bb-dynamic-form\",\n  templateUrl: \"./dynamic-form.component.html\",\n  styleUrls: [\"./dynamic-form.component.scss\"],\n})\nexport class DynamicFormComponent {\n  public form: FormGroup = new FormGroup({\n    userName: new FormControl(\"\", [Validators.required]),\n    timeRanges: new FormArray([]),\n  });\n\n  get controls() {\n    return this.form.controls;\n  }\n\n  get timeRangeControls() {\n    return this.form.get(\"timeRanges\") as FormArray;\n  }\n\n  public addNewTimeRange() {\n    this.timeRangeControls.push(this.singleRange());\n  }\n\n  public deleteTimeRange(i: number) {\n    this.timeRangeControls.removeAt(i);\n  }\n\n  private singleRange() {\n    return new FormGroup({\n      startDate: new FormControl(\"\", [Validators.required]),\n      endDate: new FormControl(\"\", [Validators.required]),\n    });\n  }\n\n  public onSubmit() {\n    console.log(this.form.getRawValue());\n  }\n}\n```\n\n```html\n\u003cform [formGroup]=\"form\" novalidate\u003e\n  \u003cdiv class=\"row\"\u003e\n    \u003cdiv class=\"col-12\"\u003e\n      \u003clabel\u003eUser Name\u003c/label\u003e\n      \u003cinput type=\"text\" formControlName=\"userName\" /\u003e\n      \u003cl9-validation-message\n        [control]=\"controls.userName\"\n      \u003e\u003c/l9-validation-message\u003e\n    \u003c/div\u003e\n\n    \u003cdiv class=\"col-12\"\u003e\n      \u003ch4\u003eTime Ranges\u003c/h4\u003e\n      \u003cng-container formArrayName=\"timeRanges\"\u003e\n        \u003cdiv\n          *ngFor=\"let _ of timeRangeControls.controls; let i = index\"\n          class=\"row\"\n        \u003e\n          \u003cng-container [formGroupName]=\"i\"\u003e\n            \u003c!-- Start Date --\u003e\n            \u003cdiv class=\"col-5\"\u003e\n              \u003clabel\u003eStart Date\u003c/label\u003e\n              \u003cinput type=\"date\" formControlName=\"startDate\" /\u003e\n              \u003cl9-validation-message\n                [control]=\"timeRangeControls.at(i).get('startDate')\"\n              \u003e\u003c/l9-validation-message\u003e\n            \u003c/div\u003e\n\n            \u003c!-- End Date --\u003e\n            \u003cdiv class=\"col-5\"\u003e\n              \u003clabel\u003eEnd Date\u003c/label\u003e\n              \u003cinput type=\"date\" formControlName=\"endDate\" /\u003e\n              \u003cl9-validation-message\n                [control]=\"timeRangeControls.at(i).get('endDate')\"\n              \u003e\u003c/l9-validation-message\u003e\n            \u003c/div\u003e\n\n            \u003cdiv class=\"col-2\"\u003e\n              \u003cbutton (click)=\"deleteTimeRange(i)\"\u003e-\u003c/button\u003e\n            \u003c/div\u003e\n          \u003c/ng-container\u003e\n        \u003c/div\u003e\n\n        \u003cdiv class=\"col-12\"\u003e\n          \u003cbutton (click)=\"addNewTimeRange()\"\u003e+\u003c/button\u003e\n        \u003c/div\u003e\n      \u003c/ng-container\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/form\u003e\n\n\u003cbutton (click)=\"onSubmit()\"\u003eSubmit form\u003c/button\u003e\n```\n\n### Custom FormGroup Validator\n\n```ts\n\n// form.component.ts\n\nimport { atLeastOneRequiredValidator } from \"./validators.ts\";\n\npublic form = new FormGroup({\n  programName: new FormGroup(\n    {\n        program: new FormControl(\"\"),\n        switch: new FormControl(\"\"),\n        intervention: new FormControl(\"\"),\n    },\n    { validators: atLeastOneRequiredValidator() },\n  ),\n});\n```\n\n```ts\n// validators.ts\nimport { ValidatorFn, FormGroup, ValidationErrors } from \"@angular/forms\";\n\nexport const atLeastOneRequiredValidator = (): ValidatorFn =\u003e {\n  return (group: FormGroup): ValidationErrors =\u003e {\n    const control1 = group.controls[\"program\"];\n    const control2 = group.controls[\"switch\"];\n    const control3 = group.controls[\"intervention\"];\n\n    if (\n      control1.value === \"\" \u0026\u0026\n      control2.value === \"\" \u0026\u0026\n      control3.value === \"\"\n    ) {\n      return { empty: true };\n    }\n\n    return null;\n  };\n};\n```\n\n### Custom FormControl Validator\n\n```ts\n// form.component.ts\nimport { PhoneNumberValidators } from \"./validators.ts\";\n\npublic form = new FormGroup({\n  phone: ['', [PhoneNumberValidators.phoneValidator()]]\n});\n```\n\n```ts\n// validators.ts\nexport class PhoneNumberValidators {\n  static phoneValidator(): ValidatorFn {\n    return (control: AbstractControl): ValidationErrors | null =\u003e {\n      if (control.value \u0026\u0026 control.value.length != 10) {\n        return { phoneNumberInvalid: true };\n      }\n      return null;\n    };\n  }\n}\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n### ControlValueAccessor\n\nWhen creating forms in Angular, sometimes you want to have an input that isn’t a standard text input, select, or checkbox. By implementing the `ControlValueAccessor` interface and registering the component as a `NG_VALUE_ACCESSOR`, you can integrate your custom form control seamlessly into template driven or reactive forms just as if it were a native input!\n\nAny component or directive can be turned into `ControlValueAccessor` by implementing the ControlValueAccessor interface and registering itself as an `NG_VALUE_ACCESSOR` provider.\n\n```ts\ninterface ControlValueAccessor {\n  writeValue(obj: any): void\n  registerOnChange(fn: any): void\n  registerOnTouched(fn: any): void\n  setDisabledState(fn: any): void\n  ...\n}\n```\n\nWrite a value to the input - `writeValue`\n\nRegister a function to tell Angular when the value of the input changes - `registerOnChange`\n\nRegister a function to tell Angular when the input has been touched - `registerOnTouched`\n\nDisable the input - `setDisabledState`\n\nThese four things make up the `ControlValueAccessor` interface, the bridge between a form control and a native element or custom input component. Once our component implements that interface, we need to tell Angular about it by providing it as a `NG_VALUE_ACCESSOR` so that it can be used.\n\nHere is the diagram that demonstrates an interaction:\n\n\u003cimg src=\"./assets//1_wvjxZqL4ZZVGmsh3VFV2Ew.jpeg\" width=\"684\" /\u003e\n\n#### Implementing custom value accessor\n\nImplementing a custom value accessor is not difficult. It requires 2 simple steps:\n\n- registering a `NG_VALUE_ACCESSOR` provider\n- implementing `ControlValueAccessor` interface methods\n\n`NG_VALUE_ACCESSOR` provider specifies a class that implements `ControlValueAccessor` interface and is used by Angular to setup synchronization with `formControl`. It’s usually the class of the component or directive that registers the provider. All form directives inject value accessors using the token `NG_VALUE_ACCESSOR` and then select a suitable accessor. If there is an accessor which is not built-in or `DefaultValueAccessor` it is selected. Otherwise Angular picks the default accessor if it’s provided. And there can be no more than one custom accessor defined for an element.\n\nSo let’s first define the provider:\n\n```ts\n\nexport const VALUE_ACCESSOR: Provider = [\n  {\n    provide: NG_VALUE_ACCESSOR,\n    useExisting: forwardRef(() =\u003e CustomFormComponent),\n    multi: true,\n  }\n];\n\n@Component({\n  selector: '',\n  providers: [...VALUE_ACCESSOR],\n  ...\n})\nexport class CustomFormComponent implements ControlValueAccessor {...}\n```\n\nOnce we defined a provider let’s implement ControlValueAccessor interface:\n\n```ts\nexport class CustomFormComponent implements ControlValueAccessor {\n  // Allow the input to be disabled, and when it is make it somewhat transparent.\n  @Input() disabled = false;\n\n  dataPropery: boolean[] = Array(5).fill(false);\n  // Function to call when the rating changes.\n  onChange = (rating: number) =\u003e {};\n  // Function to call when the input is touched (when a star is clicked).\n  onTouched = () =\u003e {};\n  // Allows Angular to update the model (rating).\n  // Update the model and changes needed for the view here.\n  writeValue(rating: number): void {\n    this.dataPropery = this.dataPropery.map((_, i) =\u003e rating \u003e i);\n    this.onChange(this.value);\n  }\n  // Allows Angular to register a function to call when the model (rating) changes.\n  // Save the function as a property to call later here.\n  registerOnChange(fn: (rating: number) =\u003e void): void {\n    this.onChange = fn;\n  }\n  // Allows Angular to register a function to call when the input has been touched.\n  // Save the function as a property to call later here.\n  registerOnTouched(fn: () =\u003e void): void {\n    this.onTouched = fn;\n  }\n  // Allows Angular to disable the input.\n  setDisabledState(isDisabled: boolean): void {\n    this.disabled = isDisabled;\n  }\n}\n```\n\n### Testing Forms\n\nThe first step is to set up the test bed for the component. Angular already provides a boilerplate for testing the component, and we’ll simply extend that:\n\n```ts\nimport { async, ComponentFixture, TestBed } from \"@angular/core/testing\";\nimport { ReactiveFormsModule } from \"@angular/forms\";\nimport { DynamicFormComponent } from \"./dynamic-form.component\";\n\ndescribe(\"DynamicFormComponent\", () =\u003e {\n  let component: DynamicFormComponent;\n  let fixture: ComponentFixture\u003cDynamicFormComponent\u003e;\n\n  beforeEach(async(() =\u003e {\n    TestBed.configureTestingModule({\n      declarations: [DynamicFormComponent],\n      imports: [ReactiveFormsModule],\n    }).compileComponents();\n  }));\n\n  beforeEach(() =\u003e {\n    fixture = TestBed.createComponent(DynamicFormComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it(\"should create\", () =\u003e {\n    expect(component).toBeTruthy();\n  });\n});\n```\n\n#### We’ll be testing our form using the following cases:\n\n1. `Form rendering`: here, we’ll check if the component generates the correct input elements when provided a formConfig array.\n2. `Form validity`: we’ll check that the form returns the correct validity state\n3. `Input validity`: we’ll check if the component responds to input in the view template\n4. `Input errors`: we’ll test for errors on the required input elements.\n\n#### Form Rendering\n\nFor this test, we’ll we’ll test that the component renders the correct elements.\n\n```ts\nit(\"should render input elements\", () =\u003e {\n  const compiled = fixture.debugElement.nativeElement;\n  const addressInput = compiled.querySelector('input[id=\"address\"]');\n  const nameInput = compiled.querySelector('input[id=\"name\"]');\n\n  expect(addressInput).toBeTruthy();\n  expect(nameInput).toBeTruthy();\n});\n```\n\n#### Form validity\n\nFor this test, we’ll check for the validity state of the form after updating the values of the input elements. For this test, we’ll update the values of the form property directly without accessing the view.\n\n```ts\nit(\"should test form validity\", () =\u003e {\n  const form = component.form;\n  expect(form.valid).toBeFalsy();\n\n  const nameInput = form.controls.name;\n  nameInput.setValue(\"John Peter\");\n\n  expect(form.valid).toBeTruthy();\n});\n```\n\nFor this test, we’re checking if the form responds to the changes in the control elements. When creating the elements, we specified that the name element is required. This means the initial validity state of the form should be `INVALID`, and the valid property of the form should be false.\n\nNext, we update the value of the name input using the `setValue` method of the form control, and then we check the validity state of the form. After providing the required input of the form, we expect the form should be valid.\n\n#### Input validity\n\nNext we’ll check the validity of the input elements. The name input is required, and we should test that the input acts accordingly. Open the spec file and add the spec below to the test suite:\n\n```ts\nit(\"should test input validity\", () =\u003e {\n  const nameInput = component.form.controls.name;\n  const addressInput = component.form.controls.address;\n\n  expect(nameInput.valid).toBeFalsy();\n  expect(addressInput.valid).toBeTruthy();\n\n  nameInput.setValue(\"John Peter\");\n  expect(nameInput.valid).toBeTruthy();\n});\n```\n\nIn this spec, we are checking the validity state of each control and also checking for updates after a value is provided.\n\nSince the name input is required, we expect its initial state to be invalid. The address isn’t required so it should be always be valid. Next, we update the value of the name input, and then we test if the valid property has been updated.\n\n#### Input errors\n\nIn this spec, we’ll be testing that the form controls contain the appropriate errors; the name control has been set as a required input. We used the `Validators` class to validate the input. The form control has an errors property which contains details about the errors on the input using key-value pairs.\n\n```ts\nit(\"should test input errors\", () =\u003e {\n  const nameInput = component.form.controls.name;\n  expect(nameInput.errors.required).toBeTruthy();\n\n  nameInput.setValue(\"John Peter\");\n  expect(nameInput.errors).toBeNull();\n});\n```\n\nFirst, we get the name form control from the form form group property. We expect the initial errors object to contain a required property, as the input’s value is empty. Next, we update the value of the input, which means the input shouldn’t contain any errors, which means the errors property should be null.\n\nIf all tests are passing, it means we’ve successfully created a form.\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Angular Routing\n\n**Resources**\n\n- [\"Angular Component Reuse Strategy\"](https://medium.com/@juliapassynkova/angular-2-component-reuse-strategy-9f3ddfab23f5/)\n- [\"How To Use Route Resolvers in Angular\"](https://www.digitalocean.com/community/tutorials/angular-route-resolvers)\n- [\"Componentless Route\"](https://netbasal.com/implementing-auth-guard-with-componentless-route-in-angular-b50a21f3bd77)\n\n### Componentless Route\n\n`Componentless routes` are useful when the same configuration apply to all child routes.\n\nFor example guards, resolvers, params, etc.,\n\n```ts\nconst routes: Routes = [\n  {\n    path: \"\",\n    component: HomeComponent,\n  },\n  {\n    path: \"\",\n    canActivateChild: [AuthGuard],\n    resolve: {\n      token: TokenNeededForBothMessagsAndContacts,\n    },\n    children: [\n      {\n        path: \"todos\",\n        component: TodosComponent,\n      },\n      {\n        path: \"blog\",\n        component: BlogComponent,\n      },\n    ],\n  },\n];\n```\n\nAnd that’s how it looks with lazy-load routes:\n\n```ts\nconst routes: Routes = [\n  {\n    path: \"\",\n    pathMatch: \"full\",\n    loadChildren: \"./home/home.module#HomeModule\",\n  },\n  {\n    path: \"\",\n    canActivateChild: [AuthGuard],\n    children: [\n      {\n        path: \"about\",\n        loadChildren: \"./about/about.module#AboutModule\",\n      },\n      {\n        path: \"posts\",\n        loadChildren: \"./posts-page/posts-page.module#PostsPageModule\",\n      },\n    ],\n  },\n];\n```\n\n### Route Resolvers\n\n`Route Resolver` allows you to get data before navigating to the new route.\n\n### Basic Implementation\n\n```ts\nimport { Injectable } from \"@angular/core\";\nimport { Resolve } from \"@angular/router\";\n\nimport { Observable, of } from \"rxjs\";\nimport { delay } from \"rxjs/operators\";\n\n@Injectable({\n  providedIn: \"root\",\n})\nexport class NewsResolver implements Resolve\u003cObservable\u003cstring\u003e\u003e {\n  resolve(): Observable\u003cstring\u003e {\n    return of(\"Resolver\").pipe(delay(1000));\n  }\n}\n```\n\n### Configuring Routes\n\n```ts\n{\n  path: 'top',\n  component: Component,\n  resolve: { message: NewsResolver }\n}\n```\n\n### Accessing the Resolved Data in the Component\n\nIn the component, you can access the resolved `data` using the data property of `ActivatedRoute’s` snapshot object\n\n```ts\nimport { ActivatedRoute } from '@angular/router';\n\n@Component({ ... })\n...\nconstructor(private route: ActivatedRoute) {}\n\nngOnInit(): void {\n  console.log(this.route.snapshot.data);\n}\n```\n\n### Resolving Data from an API\n\nFirst, add the `HttpClientModule` to `app.module.ts`\n\nThen, create a new service:\n\n```ts\nimport { Injectable } from \"@angular/core\";\nimport { HttpClient } from \"@angular/common/http\";\n\n@Injectable({\n  providedIn: \"root\",\n})\nexport class NewsService {\n  constructor(private http: HttpClient) {}\n\n  getTopPosts() {\n    return this.http.get(\n      \"https://hacker-news.firebaseio.com/v0/topstories.json\"\n    );\n  }\n}\n```\n\nAnd now you can replace the string code in `NewsResolver` with `NewsService`\n\n```ts\nimport { Injectable } from \"@angular/core\";\nimport { Resolve } from \"@angular/router\";\nimport { Observable } from \"rxjs\";\n\nimport { NewsService } from \"./news.service\";\n\nexport class NewsResolver implements Resolve\u003cany\u003e {\n  constructor(private newsService: NewsService) {}\n\n  resolve(): Observable\u003cany\u003e {\n    return this.newsService.getTopPosts();\n  }\n}\n```\n\n#### Accessing Route Parameters\n\n```ts\nimport { Injectable } from \"@angular/core\";\nimport { Resolve, ActivatedRouteSnapshot } from \"@angular/router\";\nimport { Observable } from \"rxjs\";\n\nimport { NewsService } from \"./news.service\";\n\n@Injectable({\n  providedIn: \"root\",\n})\nexport class PostResolver implements Resolve\u003cany\u003e {\n  constructor(private newsService: NewsService) {}\n\n  resolve(route: ActivatedRouteSnapshot): Observable\u003cany\u003e {\n    return this.newsService.getPost(route.paramMap.get(\"id\"));\n  }\n}\n```\n\n#### Handling Errors\n\n```ts\nimport { Injectable } from \"@angular/core\";\nimport { Resolve } from \"@angular/router\";\n\nimport { Observable, of } from \"rxjs\";\nimport { catchError } from \"rxjs/operators\";\n\nimport { NewsService } from \"./news.service\";\n\n@Injectable()\nexport class NewsResolver implements Resolve\u003cany\u003e {\n  constructor(private newsService: NewsService) {}\n\n  resolve(): Observable\u003cany\u003e {\n    return this.newsService.getTopPosts().pipe(\n      catchError(() =\u003e {\n        return of(\"data not available at this time\");\n      })\n    );\n  }\n}\n```\n\n### Custom RouteReuseStrategy\n\nRouteReuseStrategy decides on whether the router should store the current route when deactivating it or whether the router should restore it when the user re-activates it.\n\n```ts\n// app.module.ts\nimport { RouteReuseStrategy } from \"@angular/router\";\nimport { CustomReuseStrategy } from \"./router-reuse.strategy.ts\";\n\n@NgModule({\n  declarations: [],\n  imports: [],\n  providers: [{ provide: RouteReuseStrategy, useClass: CustomReuseStrategy }],\n  bootstrap: [AppComponent],\n})\nexport class AppModule {}\n```\n\n````ts\n// router-reuse.strategy.ts\nimport { Injectable } from \"@angular/core\";\nimport {\n  RouteReuseStrategy,\n  ActivatedRouteSnapshot,\n  DetachedRouteHandle,\n} from \"@angular/router\";\n/**\n * Based on Angular `DefaultRouteReuseStrategy`.\n * Reuses routes as long as their route config is the same OR until future route data has pattribute `noReuse: true`\n *\n * @example ```json\n *   {\n *       path: \"overview\",\n *       component: OverviewComponent,\n *        data: {\n *            noReuse: true,\n *        },\n *    },\n * ```\n */\n@Injectable()\nexport class CustomReuseStrategy implements RouteReuseStrategy {\n  public shouldDetach(route: ActivatedRouteSnapshot): boolean {\n    return false;\n  }\n\n  public store(\n    route: ActivatedRouteSnapshot,\n    detachedTree: DetachedRouteHandle\n  ): void {}\n\n  public shouldAttach(route: ActivatedRouteSnapshot): boolean {\n    return false;\n  }\n\n  public retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {\n    return null;\n  }\n\n  public shouldReuseRoute(\n    future: ActivatedRouteSnapshot,\n    curr: ActivatedRouteSnapshot\n  ): boolean {\n    if (future.data \u0026\u0026 Boolean(future.data.noReuse)) {\n      return !future.data.noReuse;\n    }\n    return future.routeConfig === curr.routeConfig;\n  }\n}\n````\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Unit testing\n\nTests are vital when programming because they help detect issues within your codebase that otherwise would have been missed. Writing proper tests reduces the overhead of manually testing functionality in the view or otherwise.\n\n**Resources**\n\n- [\"How to test OnPush components\"](https://medium.com/@juliapassynkova/how-to-test-onpush-components-c9b39871fe1e/)\n\n### How to test OnPush components\n\nAngular `ChangeDetectionStrategy.OnPush` is a suggested way to improve the performance of Angular applications. When a component’s `changeDetection` is `OnPush` only input ref change and output’s call will trigger the change detection mechanism for the component and all its children. However, Angular has a defect that affects testing of such components. This post shows how `TestBed.overrideComponent` helps to overcome this defect.\n\n#### Component code\n\nHere is a simple component with ChangeDetectionStrategy.OnPush\n\n```ts\n@Component({\n  selector: \"test\",\n  template: `test id = \u003cspan\u003e{{ id }}\u003c/span\u003e`,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class TestComponent {\n  @Input() id: number;\n}\n```\n\n```ts\nimport { Component } from \"@angular/core\";\nimport { TestBed, ComponentFixture, async } from \"@angular/core/testing\";\nimport { TestComponent } from \"app/app.component\";\n\ndescribe(\"TestComponent\", () =\u003e {\n  let fixture: ComponentFixture\u003cTestComponent\u003e,\n    comp: TestComponent,\n    element: HTMLElement;\n\n  beforeEach(async(() =\u003e {\n    TestBed.configureTestingModule({\n      declarations: [TestComponent],\n    });\n  }));\n\n  beforeEach(() =\u003e {\n    fixture = TestBed.createComponent(TestComponent);\n    comp = fixture.componentInstance;\n    element = fixture.debugElement.nativeElement;\n  });\n\n  it(\"can modify the id option\", async(() =\u003e {\n    comp.id = 1;\n    fixture.detectChanges();\n\n    comp.id = 2;\n    fixture.detectChanges();\n\n    expect(fixture.nativeElement.querySelector(\"span\").textContent).toContain(\n      2\n    );\n  }));\n});\n```\n\nIt fails due to a defect in Angular that fixture.detectChanges() works ONLY the first time with ChangeDetectionStrategy.OnPush and karma reports\n\n#### The solution\n\nAngular `TestBed` provides a way to override a component metadata with `overrideComponent`. Therefore, we can override `OnPush` with Default change detection just for testing and hooray test works!\n\n```ts\nTestBed.overrideComponent(TestComponent, {\n  set: new Component({\n    selector: \"test\",\n    template: `test id = \u003cspan\u003e{{id}}\u003c/span\u003e`,\n    changeDetection: ChangeDetectionStrategy.Default,\n  }),\n});\n```\n\n### How to test Custom Form Control Validator\n\n#### Validator\n\n```ts\n// password-control.validator.ts\nimport { AbstractControl, ValidationErrors, ValidatorFn } from \"@angular/forms\";\n\nconst pattern = \"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9]).{7,}\";\n\nexport class PasswordValidators {\n  static isPasswordInCorrectFormatValidator(): ValidatorFn {\n    return (control: AbstractControl): ValidationErrors | null =\u003e {\n      const reg = new RegExp(pattern);\n      if (control.value \u0026\u0026 !reg.test(String(control.value))) {\n        return { error: true };\n      }\n\n      return null;\n    };\n  }\n}\n```\n\n#### Unit tests\n\n```ts\n// password-control.validator.spec.ts\nimport { FormControl } from \"@angular/forms\";\nimport { PasswordValidators } from \"./password-control.validator\";\n\n/*\nA minimum of 7 characters\nAt least one UPPERCASE letter\nAt least one lowercase letter\nAt least one number\n*/\n\nconst TEST_CASES = [\n  {\n    test_case: \"string length is less than 7 characters\",\n    value: \"12345\",\n    result: { error: true },\n  },\n  {\n    test_case: \"string do not have UPPERCASE letter\",\n    value: \"12345qwe\",\n    result: { error: true },\n  },\n  {\n    test_case: \"string do not have lowercase letter\",\n    value: \"12345WWW\",\n    result: { error: true },\n  },\n  {\n    test_case: \"string do not have one number\",\n    value: \"qweqweWWW\",\n    result: { error: true },\n  },\n  { test_case: \"string has correct value\", value: \"123qweQW\", result: null },\n];\n\ndescribe(\"PasswordValidators\", () =\u003e {\n  const isPasswordInCorrectFormatValidator =\n    PasswordValidators.isPasswordInCorrectFormatValidator();\n  const control = new FormControl(\"input\");\n\n  TEST_CASES.forEach(({ test_case, value, result }) =\u003e {\n    it(`should return ${result} if input ${test_case}`, () =\u003e {\n      control.setValue(value);\n      expect(isPasswordInCorrectFormatValidator(control)).toEqual(result);\n    });\n  });\n});\n```\n\n### How to test Pipes\n\n#### Pipe\n\n```ts\n// string-to-number.pipe.ts\nimport { Pipe, PipeTransform } from \"@angular/core\";\n\n@Pipe({ name: \"toNumber\" })\nexport class ToNumberPipe implements PipeTransform {\n  transform(value: string | number): number {\n    if (!value) return NaN;\n\n    if (typeof value === \"string\" \u0026\u0026 value.trim().length === 0) {\n      return NaN;\n    }\n    return Number(value);\n  }\n}\n```\n\n#### Unit tests\n\n```ts\n// string-to-number.pipe.spec.ts\nimport { ToNumberPipe } from \"./string-to-number.pipe\";\n\nconst TEST_CASES = [\n  { value: 12, result: 12 },\n  { value: 12.2, result: 12.2 },\n  { value: \"12\", result: 12 },\n  { value: \"\", result: NaN },\n  { value: \" \", result: NaN },\n  { value: \"12a\", result: NaN },\n  { value: \"vv12\", result: NaN },\n];\n\ndescribe(\"ToNumberPipe\", () =\u003e {\n  const pipe = new ToNumberPipe();\n  it(\"should create a pipe instance\", () =\u003e expect(pipe).toBeTruthy());\n\n  TEST_CASES.forEach(({ value, result }) =\u003e {\n    it(`should match the ${value} with to ${result}`, () =\u003e {\n      expect(pipe.transform(value)).toEqual(result);\n    });\n  });\n});\n```\n\n### How to test Presentational components\n\n```ts\nimport { Component, EventEmitter, Input, Output } from \"@angular/core\";\n\n@Component({\n  selector: \"test-example\",\n  template: `\n    \u003ch1 class=\"title\"\u003eTest Components\u003c/h1\u003e\n    \u003cspan *ngIf=\"isSubTitleVisible\" class=\"sub-title\"\u003e sub title \u003c/span\u003e\n    \u003cbutton data-role=\"test-action-button\" (click)=\"onClick()\"\u003eclick me\u003c/button\u003e\n    \u003cbutton\n      data-role=\"test-action-with-param-button\"\n      (click)=\"onClickWithParam('string param')\"\n    \u003e\n      click me with data\n    \u003c/button\u003e\n  `,\n})\nexport class TestComponent {\n  @Input() public isSubTitleVisible = false;\n  @Output() public click = new EventEmitter\u003c{ someData: string }\u003e();\n  @Output() public clickWithParam = new EventEmitter\u003cstring\u003e();\n\n  public onClick() {\n    this.click.emit({ someData: \"test string\" });\n  }\n\n  public onClickWithParam(event: string) {\n    this.clickWithParam.emit(event);\n  }\n}\n```\n\n#### Unit tests\n\n```ts\nimport { ComponentFixture, TestBed } from \"@angular/core/testing\";\nimport { By } from \"@angular/platform-browser\";\n\nimport { TestComponent } from \"./test.component\";\n\ndescribe(\"TestComponent\", () =\u003e {\n  let component: TestComponent;\n  let fixture: ComponentFixture\u003cTestComponent\u003e;\n  let title: HTMLElement;\n  let actionButton: HTMLButtonElement;\n  let actionButtonWithParam: HTMLButtonElement;\n\n  beforeEach(() =\u003e {\n    TestBed.configureTestingModule({\n      imports: [],\n      declarations: [TestComponent],\n    });\n  });\n\n  beforeEach(() =\u003e {\n    fixture = TestBed.createComponent(TestComponent);\n    component = fixture.debugElement.componentInstance;\n\n    fixture.detectChanges();\n\n    title = fixture.debugElement.query(By.css(\".title\"))\n      .nativeElement as HTMLElement;\n    actionButton = fixture.debugElement.query(\n      By.css(\"button[data-role='test-action-button']\")\n    ).nativeElement as HTMLButtonElement;\n    actionButtonWithParam = fixture.debugElement.query(\n      By.css(\"button[data-role='test-action-with-param-button']\")\n    ).nativeElement as HTMLButtonElement;\n  });\n\n  it(\"should create\", () =\u003e {\n    expect(component).toBeTruthy();\n  });\n\n  it(\"should contain title and sub_title\", () =\u003e {\n    component.isSubTitleVisible = true;\n    fixture.detectChanges();\n    const sub_title = fixture.debugElement.query(By.css(\".sub-title\"))\n      .nativeElement as HTMLElement;\n\n    expect(title).toBeTruthy();\n    expect(sub_title).toBeTruthy();\n\n    expect(title.textContent?.trim()).toEqual(\"Test Components\");\n    expect(sub_title.textContent?.trim()).toMatch(\"sub title\");\n  });\n\n  it(\"should emit when button is clicked\", () =\u003e {\n    spyOn(component.click, \"emit\");\n    actionButton.click();\n    expect(component.click.emit).toHaveBeenCalled();\n    expect(component.click.emit).toHaveBeenCalledWith({\n      someData: \"test string\",\n    });\n  });\n\n  it(\"should emit when button with param is clicked\", () =\u003e {\n    spyOn(component.clickWithParam, \"emit\");\n    actionButtonWithParam.click();\n    expect(component.clickWithParam.emit).toHaveBeenCalled();\n    expect(component.clickWithParam.emit).toHaveBeenCalledWith(\"string param\");\n  });\n\n  it(\"should check visibility of subTitle based on isSubTitleVisible property\", () =\u003e {\n    component.isSubTitleVisible = false;\n    fixture.detectChanges();\n    const subTitleHidden = fixture.debugElement.query(By.css(\".sub-title\"));\n\n    expect(subTitleHidden).toBeNull();\n\n    component.isSubTitleVisible = true;\n    fixture.detectChanges();\n\n    const subTitleVisible = fixture.debugElement.query(By.css(\".sub-title\"))\n      .nativeElement as HTMLElement;\n\n    expect(subTitleVisible).toBeTruthy();\n    expect(subTitleVisible.textContent?.trim()).toMatch(\"sub title\");\n  });\n});\n```\n\n### How to test HTTP service\n\n```ts\n// post.service.ts\nimport { HttpClient, HttpHeaders } from \"@angular/common/http\";\nimport { Injectable } from \"@angular/core\";\nimport { Observable, of } from \"rxjs\";\nimport { catchError } from \"rxjs/operators\";\n\nexport interface Post {\n  id: string;\n  title: string;\n}\n\n@Injectable({\n  providedIn: \"root\",\n})\nexport class PostsService {\n  url = \"https://jsonplaceholder.typicode.com\";\n\n  httpOptions = {\n    headers: new HttpHeaders({ \"Content-Type\": \"application/json\" }),\n  };\n\n  constructor(private http: HttpClient) {}\n\n  getAllPosts(): Observable\u003cPost[]\u003e {\n    return this.http\n      .get\u003cPost[]\u003e(`${this.url}/posts`)\n      .pipe(catchError(this.handleError\u003cPost[]\u003e(\"getAllPosts\", [])));\n  }\n\n  getPostById(id: string): Observable\u003cPost\u003e {\n    return this.http\n      .get\u003cPost\u003e(`${this.url}/posts/${id}`)\n      .pipe(catchError(this.handleError\u003cPost\u003e(`getPostById id=${id}`)));\n  }\n\n  updatePost(post: Post): Observable\u003cany\u003e {\n    return this.http\n      .put(`${this.url}/posts`, post, this.httpOptions)\n      .pipe(catchError(this.handleError\u003cany\u003e(`updatePost`)));\n  }\n\n  addPost(post: Post): Observable\u003cPost\u003e {\n    return this.http\n      .post\u003cPost\u003e(`${this.url}/posts`, post, this.httpOptions)\n      .pipe(catchError(this.handleError\u003cPost\u003e(`addPost`)));\n  }\n\n  deletePost(post: Post): Observable\u003cPost\u003e {\n    return this.http\n      .delete\u003cPost\u003e(`${this.url}/posts/${post.id}`, this.httpOptions)\n      .pipe(catchError(this.handleError\u003cPost\u003e(`deletePost`)));\n  }\n\n  private handleError\u003cT\u003e(operation = \"operation\", result?: T) {\n    return (error: any): Observable\u003cT\u003e =\u003e {\n      console.error(`${operation} failed: ${error.message}`);\n\n      return of(result as T);\n    };\n  }\n}\n```\n\n#### Unit tests\n\n```ts\n// post.service.spec.ts\nimport { TestBed } from \"@angular/core/testing\";\nimport { Post, PostsService } from \"./post.service\";\nimport {\n  HttpClientTestingModule,\n  HttpTestingController,\n} from \"@angular/common/http/testing\";\n\nconst postsMock: Post[] = [\n  {\n    id: \"3\",\n    title: \"sit aut\",\n  },\n  {\n    id: \"4\",\n    title: \"eum et est occaecati\",\n  },\n];\n\ndescribe(\"[SERVICES]: PostsService\", () =\u003e {\n  let service: PostsService;\n  let httpController: HttpTestingController;\n  let url = \"https://jsonplaceholder.typicode.com\";\n\n  beforeEach(() =\u003e {\n    TestBed.configureTestingModule({\n      imports: [HttpClientTestingModule],\n      providers: [PostsService],\n    });\n\n    service = TestBed.inject(PostsService);\n    httpController = TestBed.inject(HttpTestingController);\n  });\n\n  it(\"should be initialized with default state\", () =\u003e {\n    expect(service).toBeTruthy();\n  });\n\n  it(\"should call getAllPosts and return an array of Posts\", () =\u003e {\n    service.getAllPosts().subscribe((res) =\u003e {\n      expect(res).toEqual(postsMock);\n    });\n\n    const req = httpController.expectOne({\n      method: \"GET\",\n      url: `${url}/posts`,\n    });\n\n    req.flush(postsMock);\n  });\n\n  it(\"should call getPostById and return the appropriate Book\", () =\u003e {\n    const id = \"1\";\n\n    service.getPostById(id).subscribe((data) =\u003e {\n      expect(data).toEqual(postsMock[0]);\n    });\n\n    const req = httpController.expectOne({\n      method: \"GET\",\n      url: `${url}/posts/${id}`,\n    });\n\n    req.flush(postsMock[0]);\n  });\n\n  it(\"should call updatePost and return the updated Post from the API\", () =\u003e {\n    const updatedPost: Post = { id: \"1\", title: \"New title\", body: \"Author 1\" };\n\n    service.updatePost(postsMock[0]).subscribe((data) =\u003e {\n      expect(data).toEqual(updatedPost);\n    });\n\n    const req = httpController.expectOne({\n      method: \"PUT\",\n      url: `${url}/posts`,\n    });\n\n    req.flush(updatedPost);\n  });\n\n  it(\"should call addPost and return the add Post from the API\", () =\u003e {\n    service.addPost(postsMock[0]).subscribe((data) =\u003e {\n      expect(data).toEqual(postsMock[0]);\n    });\n\n    const req = httpController.expectOne({\n      method: \"POST\",\n      url: `${url}/posts`,\n    });\n\n    req.flush(postsMock[0]);\n  });\n\n  it(\"should call addPost and return the add Post from the API\", () =\u003e {\n    service.deletePost(postsMock[1]).subscribe((data) =\u003e {\n      expect(data).toEqual(postsMock[1]);\n    });\n\n    const req = httpController.expectOne({\n      method: \"DELETE\",\n      url: `${url}/posts/4`,\n    });\n\n    req.flush(postsMock[1]);\n  });\n});\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Error Handling\n\nLearn how to automatically catch all errors in a web application written in Angular and process them accordingly\n\n**Resources**\n\n- [\"Global Error Handling in Angular\"](https://pkief.medium.com/global-error-handling-in-angular-ea395ce174b1)\n\n- [\"Error Handling \u0026 Angular\"](https://medium.com/@aleixsuau/error-handling-angular-859d529fa53a)\n\n### Errors, Exceptions \u0026 CallStack\n\nWhen an Error happens, an Exception is thrown at the current point of execution and it will remove (unwind) every function of the CallStack until the exception is handled by a try/catch block. Then, the control will continue from the statement right after the catch block.\n\n`If no try/catch block is found, the Exception will remove all the functions of the CallStack, crashing completely our app`.\n\n```ts\n\nfireError() {\n  const shthppns = r; // r is not defined === ReferenceError\n  console.log(\"I won't be logged\");\n}\n\nfireErrorWithNet() {\n  try {\n    const shthppns = r; // r is not defined === ReferenceError\n  } catch (error) {\n    console.log('\u003e Error is handled: ', error.name);\n  }\n  console.log('\u003e And Control continues from this statement');\n}\n```\n\nAs you can see in the code, the try/catch block prevents the app from crashing and lets the program continue right below the catch.\n\n#### The Client Errors\n\nSince we as the developers don’t know where and when such an error could occur, it is important to catch all occurring errors at a central location\n\nA client error should contain:\n\n- name (ie: `ReferenceError`).\n- message (ie: `X is not defined`).\n\nAnd in most modern browsers: `fileName`, `lineNumber` and `columnNumber` where the error happened, and stack (last X functions called before the error).\n\n#### The Server Errors\n\nIt is clear that the error is coming from the back end, there is a need to take care of the error handling for every single request to the back end. Again, it is better to handle these errors in a centralized location so that the user is presented with consistent error messages and also to avoid forgetting to intercept errors.\n\nA server error might contain:\n\n- `status` (or code): Code status starting with 4 (4xx…).\n- `name`: The name of the error (ie: `HttpErrorResponse`).\n- `message`: Explanation message (ie: Http failure response for…).\n\n### Global Error Handler\n\nBy default, Angular comes with its own `ErrorHandler` that intercepts all the Errors that happen in our app and logs them to the console, preventing the app from crashing.\nWe can modify this default behavior by creating a new class that implements the `ErrorHandler`\nInside the `ErrorHandler`, we can check which kind of error it is\n\n```ts\n// global-error-handler.ts\nimport { ErrorHandler, Injectable, Injector } from \"@angular/core\";\nimport { HttpErrorResponse } from \"@angular/common/http\";\nimport { environment } from \"@env/environment\";\n\n@Injectable()\nexport class GlobalErrorHandler implements ErrorHandler {\n  constructor(private injector: Injector) {}\n\n  handleError(error: Error | HttpErrorResponse) {\n    if (error instanceof HttpErrorResponse) {\n      // Server error happened\n      this.handleServerError(error);\n    } else {\n      // Client Error Happend\n      this.handleClientError(error);\n    }\n  }\n\n  // Customize the default server error handler here if needed\n  private handleServerError(error: HttpErrorResponse) {\n    if (!navigator.onLine) {\n      // No Internet connection\n      alert(\"No Internet Connection\");\n    }\n\n    if (!environment.production) {\n      // Http Error\n      // Show notification to the user\n      console.error(\"Request error\", error);\n      alert(`${error.status} - ${error.message}`);\n    }\n  }\n\n  private handleClientError(error: Error) {\n    console.error(error);\n  }\n}\n```\n\nBecause the best Error is the one that never happens, we could improve our error handling using an `HttpInterceptor` that would intercept all the server calls and retry them X times before throw an Error\n\n```ts\n// http-error.interceptor.ts\nimport { Injectable } from \"@angular/core\";\nimport {\n  HttpEvent,\n  HttpInterceptor,\n  HttpHandler,\n  HttpRequest,\n} from \"@angular/common/http\";\nimport { Observable } from \"rxjs\";\nimport { finalize, retry } from \"rxjs/operators\";\n\nimport { LoaderService } from \"@core/services/loader.service\";\n\n@Injectable({\n  providedIn: \"root\",\n})\nexport class HttpErrorInterceptor implements HttpInterceptor {\n  constructor(public loaderService: LoaderService) {}\n\n  intercept(\n    request: HttpRequest\u003cany\u003e,\n    next: HttpHandler\n  ): Observable\u003cHttpEvent\u003cany\u003e\u003e {\n    this.loaderService.display(true);\n    // If the call fails, retry until 2 times before throwing an error\n    return next.handle(request).pipe(\n      retry(2),\n      finalize(() =\u003e {\n        this.loaderService.display(false);\n      })\n    );\n  }\n}\n```\n\nFor Error Handling we need to register two `providers`. The first one is responsible for the general error handling, which catches all errors occurring within our application. The second provider is an HTTP interceptor, which is called for every interaction with the back end. The multi property must always be set to `true` in this case, since the `HTTP_INTERCEPTORS` injection token can potentially be assigned to several classes.\n\n```ts\n// core.module.ts\n@NgModule({\n  imports: [ ... ],\n  declarations: [ ... ],\n  providers: [\n    {\n      provide: ErrorHandler,\n      useClass: GlobalErrorHandler,\n    },\n    {\n      provide: HTTP_INTERCEPTORS,\n      useClass: HttpErrorInterceptor,\n      multi: true,\n    },\n  ]\n})\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## JWT Token Interceptor\n\n```ts\nimport { Injectable, Injector, ErrorHandler } from \"@angular/core\";\nimport {\n  HttpEvent,\n  HttpInterceptor,\n  HttpHandler,\n  HttpResponse,\n  HttpRequest,\n  HttpErrorResponse,\n} from \"@angular/common/http\";\nimport { Observable, of } from \"rxjs\";\nimport { tap } from \"rxjs/operators\";\n\n@Injectable()\nexport class TokenInterceptor implements HttpInterceptor {\n  constructor() {}\n\n  intercept(\n    request: HttpRequest\u003cany\u003e,\n    next: HttpHandler\n  ): Observable\u003cHttpEvent\u003cany\u003e\u003e {\n    request = request.clone({\n      setHeaders: {\n        Authorization: `Bearer token`,\n      },\n    });\n\n    return next.handle(request);\n  }\n}\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Angular Dynamic Components\n\nComponent templates are not always fixed. An application may need to load new components at runtime.\n\nThis cookbook shows you how to use `ComponentFactoryResolver` to add components dynamically.\n\nIn the component, we are creating a template element. We are also using the hash symbol (#) to declare a reference variable named `dynamicLoadDevicesComponent`. The template element is the place, or in the Angular world, the container.\n\n```html\n\u003ctemplate #dynamicLoadDevicesComponent\u003e\u003c/template\u003e\n```\n\nWe can get a reference to the template element with the ViewChild decorator that also takes a local variable as a parameter\n\n```ts\n@ViewChild(\"dynamicLoadDevicesComponent\", {read: ViewContainerRef, static: true }) private entry: ViewContainerRef;\n```\n\nBefore we proceed to the createComponent() method, we need to add one more service\n\n```ts\nconstructor(private resolver: ComponentFactoryResolver) {}\n```\n\nThe `ComponentFactoryResolver` service exposes one primary method, `resolveComponentFactory`.\nThe `resolveComponentFactory()` method takes a component and returns a `ComponentFactory`.\nYou can think of `ComponentFactory` as an object that knows how to create a component.\nAs you can see the `ComponentFactory` exposes the `create()` method that will be used by the container ( ViewContainerRef ) internally.\n\n```ts\nprivate createComponent() {\n  this.entry.clear();\n  const factory = this.resolver.resolveComponentFactory(RedDeviceComponent);\n  this.componentRef = this.entry.createComponent(factory);\n}\n```\n\nLet’s explain what is happening piece by piece.\n\n```ts\nthis.entry.clear();\n```\n\nEvery time we need to create the component we need to remove the previous view, otherwise, it will append more components to the container. (not required if you need multiple components)\n\n```ts\nconst factory = this.resolver.resolveComponentFactory(RedDeviceComponent);\nthis.componentRef = this.entry.createComponent(factory);\n```\n\nThe resolveComponentFactory() method takes a component and returns the recipe for how to create a component.\n\nAnd don’t forget to destroy the component\n\n```ts\npublic ngOnDestroy() {\n  this.componentRef.destroy();\n}\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Dynamic Importing 3rd-party Libraries\n\n**Resources**\n\n- [\"Angular: Dynamic Importing Large Libraries\"](https://medium.com/lacolaco-blog/angular-dynamic-importing-large-libraries-8ec079603d0/)\n\n#### Use import()\n\n`import()` is a new feature of `ECMAScript`. It loads a script dynamically in runtime. In the future, all modern browsers support it natively. But today, its support is not enough.\n\n### Preparation: Edit tsconfig.json\n\nAlso, `TypeScript` has support for dynamic `import()`, but it is enabled only in some module types\n\n```json\n{\n  \"compileOnSave\": false,\n  \"compilerOptions\": {\n    \"baseUrl\": \"./\",\n    \"outDir\": \"./dist/out-tsc\",\n    \"sourceMap\": true,\n    \"declaration\": false,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"importHelpers\": true,\n    \"target\": \"es5\",\n    \"typeRoots\": [\"node_modules/@types\"],\n    \"lib\": [\"es2018\", \"dom\"]\n  }\n}\n```\n\n#### Migrate to dynamic import()\n\nCall import() in the TypeScript code simply like following:\n\n```ts\nconst importChart = normalizeCommonJSImport(\n  import(/* webpackChunkName: \"chart\" */ \"chart.js\")\n);\n```\n\n`normalizeCommonJSImport` is a utility function for compatibility between `CommonJS` module and `ES modules` and for strict-typing.\n\n```ts\nexport function normalizeCommonJSImport\u003cT\u003e(\n  importPromise: Promise\u003cT\u003e\n): Promise\u003cT\u003e {\n  // CommonJS's `module.exports` is wrapped as `default` in ESModule.\n  return importPromise.then((m: any) =\u003e (m.default || m) as T);\n}\n```\n\nIn this case, TypeScript’s `import()` returns `Promise\u003ctypeof Chart\u003e` as well as `import * as Chart from ‘chart.js’`. This is a problem because `chart.js` is a `CommonJS` module. Without any helpers,default doesn’t exist in the result of `import()` . So we have to mark it as any temporary and remark default as the original type. This is a small hack for correct typing.\n\nAs the result, you can see separated bundles like below. `chart.\u003chash\u003e.js` is not marked as `[initial]`; it means this bundle is loaded lazily and doesn’t affect initial bootstrapping.\n\n\u003cimg src=\"./assets/1_FY_MPUG_xp4BXeWVfZaTXg.png\" width=\"100%\" /\u003e\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Unsubscribe from Observables\n\n### Use Async | Pipe\n\nThe async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. When a new value is emitted, the async pipe marks the component to be checked for changes. When the component gets destroyed, the asyncpipe unsubscribes automatically to avoid potential memory leaks.\nUsing it in our AppComponent:\n\n```ts\n@Component({\n    ...,\n    template: `\n        \u003cdiv\u003e\n         Interval: {{observable$ | async}}\n        \u003c/div\u003e\n    `\n})\nexport class AppComponent implements OnInit {\n    observable$\n    ngOnInit () {\n        this.observable$ = Rx.Observable.interval(1000);\n    }\n}\n```\n\nOn instantiation, the AppComponent will create an Observable from the interval method. In the template, the Observable observable$ is piped to the async Pipe. The async pipe will subscribe to the observable$ and display its value in the DOM. async pipe will unsubscribe the observable\\$ when the AppComponent is destroyed. async Pipe has ngOnDestroy on its class so it is called when the view is contained in is being destroyed.\nUsing the async pipe is a huge advantage if we are using Observables in our components because it will subscribe to them and unsubscribe from them. We will not be bothered about forgetting to unsubscribe from them in ngOnDestroy when the component is being killed off.\n\n### Unsubscribing Declaratively with takeUntil\n\nThe solution is to compose our subscriptions with the takeUntil operator and use a subject that emits a truthy value in the ngOnDestroy lifecycle hook.\n\nThe following snippet does the exact same thing, but this time we unsubscribe declaratively. You’ll notice that an added benefit is that we don’t need to keep references to our subscriptions anymore:\n\n```ts\n\nimport { Observable } from 'rxjs/Observable';\nimport { Subject } from 'rxjs/Subject';\nimport 'rxjs/add/observable/interval';\nimport 'rxjs/add/operator/takeUntil';\n\n@Component({ ... })\nexport class AppComponent implements OnInit, OnDestroy {\n  destroy$: Subject\u003cboolean\u003e = new Subject\u003cboolean\u003e();\n\n  constructor() {}\n\n  ngOnInit(){\n    Observable\n      .interval(250)\n      .takeUntil(this.destroy$)\n      .subscribe(val =\u003e {\n        console.log('Current value:', val);\n      });\n  }\n\n  ngOnDestroy() {\n    this.destroy$.next(true);\n    // Now let's also unsubscribe from the subject itself:\n    this.destroy$.unsubscribe();\n  }\n```\n\nNote that Using an operator like takeUntil instead of manually unsubscribing will also complete the observable, triggering any completion event on the observable\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Containerizing Angular using Docker\n\n`Docker` is a popular virtualization tool that replicates a specific operating environment on top of a host OS. Each environment is called a container\n\nA `container` uses an image of a preconfigured operating system optimized for a specific task. When a Docker image is launched, it exists in a container. For example, multiple containers may run the same image at the same time on a single host operating system\n\n**Resources**\n\n- [\"Build and run Angular application in a Docker container\"](https://wkrzywiec.medium.com/build-and-run-angular-application-in-a-docker-container-b65dbbc50be8/)\n- [\"Containerizing Angular application for production using Docker\"](https://dev.to/usmslm102/containerizing-angular-application-for-production-using-docker-3mhi/)\n- [\" To List / Start / Stop Docker Containers\"](https://phoenixnap.com/kb/how-to-list-start-stop-docker-containers/)\n\n**Pre-requisites**\n\n- [\"Install Docker for Desktop\"](https://www.docker.com/products/docker-desktop)\n\n### Creating Docker file\n\nThen create a new file called `Dockerfile` that will be located in the project’s `root` folder. It should have these following lines:\n\n#### Complete Dockerfile\n\n```dockerfile\n### STAGE 1: Build ###\nFROM node:12.20-alpine3.10 AS build\nWORKDIR /app\nCOPY package.json package-lock.json ./\nRUN npm install\nCOPY . .\nRUN npm run build:prod\n\n### STAGE 2: Run ###\nFROM nginx:1.17.1-alpine\nCOPY --from=build /app/dist/ngx-levi9 /usr/share/nginx/html\n```\n\n#### STAGE 1: Build\n\n```ts\nFROM node:12.20-alpine3.10 As build\n```\n\nThis line will tell the docker to pull the node image with tag `12.20-alpine3.10` if the images don't exist. We are also giving a friendly name `build` to this image so we can refer it later.\n\n```ts\nWORKDIR / app;\n```\n\nThis `WORKDIR` command will create the working directory in our docker image. going forward any command will be run in the context of this directory.\n\n```ts\nCOPY package.json package-lock.json ./\n```\n\nThis `COPY` command will copy `package.json` and `package-lock.json` from our current directory to the root of our working directory inside a container which is `/app`.\n\n```ts\nRUN npm install\n```\n\nThis RUN command will restore node_modules define in our package.json\n\n```ts\nCOPY . .\n```\n\nThis `COPY` command copies all the files from our current directory to the container working directory. this will copy all our source files\n\n```ts\nRUN npm run build:prod\n```\n\nThis command will build our angular project in production mode and create production ready files in dist/appName folder\n\n#### STAGE 2: Run\n\n```ts\nFROM nginx:1.17.1-alpine\n```\n\nThis line will create a second stage `nginx` container where we will copy the compiled output from our build stage\n\n```ts\nCOPY --from=build /app/dist/ngx-levi9 /usr/share/nginx/html\n```\n\nThis is the final command of our docker file. This will copy the compiled angular app from builder stage path `/app/dist/ngx-levi9` to `nginx` container\n\n### Creating docker ignore file\n\nWhen `COPY . .` command execute it will copy all the files in the host directory to the container working directory. if we want to ignore some folder like `.git` or `node_modules` we can define these folders in `.dockerignore` file\n\n```ts\n.git\nnode_modules\n```\n\n### Building a docker image\n\nNavigate the project folder in command prompt and run the below command to build the image\n\n```npm\ndocker build . -t dockerngstart .\n```\n\nThis command will look for a docker file in the current directory and create the image with tag `dockerngstart`. with `-t` command you can specify the tag for the image the default convention is `\u003cDockerHubUsername\u003e/\u003cImageName\u003e`.\n\n### Running a container\n\nYou can run the docker image using the below command\n\n```npm\ndocker run --name dockerngstart-container -it -p 8000:80 dockerngstart\n```\n\nA container may be running, but you may not be able to interact with it. To start the container in interactive mode, use the `–i` and `–t` options\n\nNavigate to your browser with `http://localhost:8000`\n\n### Review docker images\n\nRun `docker images` command to list all the docker images in your machine\n\n```ts\ndocker images\n```\n\n\u003cimg src=\"./assets/docker images.png\" width=\"100%\" /\u003e\n\n### Remove docker image\n\n```ts\ndocker rmi \u003cIMAGE ID\u003e\n```\n\n### List Docker Containers\n\nTo list all running Docker containers, enter the following into a terminal window\n\n```ts\ndocker ps\n```\n\nTo list all containers, both running and stopped, add `–a`\n\n```ts\ndocker ps -a\n```\n\n### Start Docker Container\n\nThe main command to launch or start a single or multiple stopped Docker containers is docker start:\n\n```ts\ndocker start [options] container_id\n```\n\nTo create a new container from an image and start it, use `docker run`\n\n```ts\ndocker run [options] image [command] [argument]\n```\n\n### Stop Docker Container\n\nBy default, you get a 10 second grace period. The stop command instructs the container to stop services after that period. Use the --time option to define a different grace period expressed in seconds\n\n```ts\ndocker stop [option] container_id\n\ndocker stop --time=20 container_id\n```\n\nTo immediately kill a docker container without waiting for the grace period to end use:\n\n```ts\ndocker kill [option] container_id\n```\n\nTo stop all running containers, enter the following:\n\n```ts\ndocker stop $(docker ps –a –q)\n```\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Angular Schematics\n\n**Resources**\n\n- [\"Authoring schematics\"](https://angular.io/guide/schematics-authoring/)\n\n- [\"Use Angular Schematics to Simplify Your Life\"](https://developer.okta.com/blog/2019/02/13/angular-schematics/)\n\n- [\"Extend Angular Schematics to customize your development process\"](https://indepth.dev/posts/1438/extend-angular-schematics-to-customize-your-development-process/)\n\nA schematic is a template-based code generator that supports complex logic. It is a set of instructions for transforming a software project by generating or modifying code. Schematics are packaged into collections and installed with npm.\n\nThe schematic collection can be a powerful tool for creating, modifying, and maintaining any software project, but is particularly useful for customizing Angular projects to suit the particular needs of your own organization. You might use schematics, for example, to generate commonly-used UI patterns or specific components, using predefined templates or layouts. Use schematics to enforce architectural rules and conventions, making your projects consistent and inter-operative\n\nHere is a short list of steps to implement a custom schematic that overrides the default angular one:\n\n- create a blank schematic using the built-in command\n- implement schematic\n  - factory function\n  - template file\n  - schema with input parameters definitions\n  - collection, which defines exposed schematics\n- add schematic to Angular project\n\n### Schematics CLI\n\nSchematics come with their own command-line tool. Using Node 6.9 or later, install the Schematics command line tool globally:\n\n```npm\n$ npm install -g @angular-devkit/schematics-cli\n```\n\nThen run schematics to create a new blank project:\n\n```npm\n$ schematics blank --name=my-component\n```\n\nThe blank schematic command will create a project with configured typescript, package.json, and initial schematic. The structure of the project should look like this\n\n```npm\nCREATE my-component/README.md (639 bytes)\nCREATE my-component/.gitignore (191 bytes)\nCREATE my-component/.npmignore (64 bytes)\nCREATE my-component/package.json (569 bytes)\nCREATE my-component/tsconfig.json (656 bytes)\nCREATE my-component/src/collection.json (231 bytes)\nCREATE my-component/src/my-component/index.ts (318 bytes)\nCREATE my-component/src/my-component/index_spec.ts (503 bytes)\n```\n\n`collections.json` - this is the main file, in which are defined all schematics that this project will expose\n\n```json\n{\n  \"$schema\": \"../node_modules/@angular-devkit/schematics/collection-schema.json\",\n  \"schematics\": {\n    \"my-component\": {\n      \"description\": \"A blank schematic.\",\n      \"factory\": \"./my-component/index#newModuleSchematics\",\n      \"schema\": \"./my-component/schema.json\"\n    }\n  }\n}\n```\n\nYou can see that the my-component schematic points to a factory function in `my-component/index.ts`. Crack that open and you’ll see the following\n\n```typescript\nimport { Rule, SchematicContext, Tree } from \"@angular-devkit/schematics\";\n\nexport function myComponent(_options: any): Rule {\n  return (tree: Tree, _context: SchematicContext) =\u003e {\n    return tree;\n  };\n}\n```\n\nOne cool thing about Schematics is they don’t perform any direct actions on your filesystem. Instead, you specify what you’d like to do to a Tree. The Tree is a data structure with a set of files that already exist and a staging area (of files that will contain new/updated code). You can see in the code above that nothing is really happening, the test even proves the tree is empty!\n\nLet’s briefly understand the factory function’s critical elements, which we will later use during the implementation.\n\n`_options` - an object that keeps all input data from a caller. We will use it to get additional inputs as well as the name of the component\n`Rule` - it’s an object that defines the transformations of the Tree. All we need to know, for now, is that we will need to build that, and this will precisely define files generation with the rules applicable to them.\n\n### Copy and Manipulate Templates\n\nWriting a template is a relatively easy job because it should look the same as well known generated file, except for one difference - all dynamic content, for example, the name of a component, has to be written inside special tags (\u003c%= , %\u003e), to print the value.\n\nTemplate files are stored inside `/files` directory, and their names should be written using a specific format to allow dynamic naming of the files. For our case, we want to create a typescript file that will be in the form component-name.component.ts, assuming the \"component-name\" is our name provided as an input. To fulfill that, we need to create a template file with the name: `__name@dasherize__`.component.ts. Double underscore separates the dynamic content from the plain string, and the dasherize is an Angular function that will make a \"kebab-case\" string from the name. We have to use the same approach for naming a directory, so we need to place a template file within a folder called `__name@dasherize__`.\n\nExample\n\n```typescript\n// __name@dasherize__.component.ts\nimport { Component, OnInit } from '@angular/core';\n\n@Component({\n\tselector: 'app-\u003c%= dasherize(name) %\u003e-component',\n\ttemplateUrl: './\u003c%= dasherize(name) %\u003e.component.html',\n\tstyleUrls: ['./\u003c%= dasherize(name) %\u003e.component.scss'],\n})\nexport class \u003c%= classify(name) %\u003eComponent implements OnInit {\n\n    constructor() { }\n\n    ngOnInit(): void {\n    }\n}\n```\n\n### We are running a schematic!\n\nFirst things first, we need to build our library with a schematic. Use the command below in the library directory\n\n```npm\nnpm run build\n```\n\nRun the following command from the my-component directory.\n\n```npm\nschematics .:my-component --dry-run=false\n```\n\nThis looks like it creates a file, but it does not. This is because schematics runs in debug mode by default. You can bypass by adding `--dry-run=false` to the command. Run `schematics .:my-component --dry-run=false`. If you try running the command again, it’ll fail because the file already exists.\n\n```npm\nschematics .:my-component --dry-run=false\nAn error occured:\nError: Path \"/hello.ts\" already exist.\n```\n\nWhen using `Schematics`, it’s unlikely you’re going to want to create files and their contents manually. More than likely, you’ll want to copy templates, manipulate their contents, and put them in the project you’re modifying. Luckily, there’s an API for that!\n\n\u003cimg src=\"https://miro.medium.com/max/700/0*Piks8Tu6xUYpF4DU\" width=\"100%\" height=\"17px\" style=\"padding: 2px 1rem; background-color: #fff\"\u003e\n\n## Performance\n\n**Resources**\n\n- [\"Performance Analysis with webpack Bundle Analyzer\"](https://www.digitalocean.com/community/tutorials/angular-angular-webpack-bundle-analyzer/)\n\nWeb performance is possibly one of the most important parts to take into account for a modern web application. The thing is, it’s easier than ever to add third party modules and tools to our projects, but this can come with a huge performance tradeoff.\n\nThis becomes even more difficult the larger a project becomes, therefore, this article looks at how to use webpack Bundle Analyzer with Angular to help visualize where code in the final bundle comes from.\n\n### Webpack Bundle Analyzer\n\nLet’s install the webpack-bundle-analyzer plugin:\n\n```npm\n$ npm i webpack-bundle-analyzer -D\n```\n\nBuilding with stats.json:\n\nThe Angular CLI gives us the ability to build with a `stats.json` out of the box. This allows us to pass this to our bundle analyzer and start the process.\n\nWe can add a new script to `package.json` to add this functionality:\n\n```ts\n\"scripts\": {\n  \"build:stats\": \"ng build --stats-json\",\n  \"analyze\": \"webpack-bundle-analyzer dist/AngularBundleAnalyser/stats.json\"\n}\n```\n\nNow we can run npm run build:stats to generate a stats.json file inside of the dist folder! Let’s do that:\n\n```ts\n$ npm run build:stats\n```\n\nRun the analyzer with the following command:\n\n```ts\n$ npm run analyze\n```\n\nResult:\n\u003cimg src=\"./assets/webpack-bundle-analysis-2.png\" width=\"960px\" /\u003e\n","funding_links":[],"categories":["Others","Bachelor-Level"],"sub_categories":["Bachelor Informatik/KI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FlubkoKuzenko%2Fangular-clean-code","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FlubkoKuzenko%2Fangular-clean-code","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FlubkoKuzenko%2Fangular-clean-code/lists"}