{"id":57319,"url":"https://github.com/fetis/30-seconds-of-angular","name":"30-seconds-of-angular","description":"Curated collection of Angular snippets that you can understand in 30 seconds or less","projects_count":40,"last_synced_at":"2026-10-15T07:00:23.561Z","repository":{"id":42246658,"uuid":"174430298","full_name":"fetis/30-seconds-of-angular","owner":"fetis","description":"Curated collection of Angular snippets that you can understand in 30 seconds or less","archived":false,"fork":false,"pushed_at":"2023-01-04T16:26:55.000Z","size":1616,"stargazers_count":35,"open_issues_count":55,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2026-09-23T17:54:08.703Z","etag":null,"topics":["angular","awesome-list","javascript","learn-to-code","learning-resources","programming","snippets","snippets-collection"],"latest_commit_sha":null,"homepage":"https://30.codelab.fun","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fetis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-03-07T22:34:06.000Z","updated_at":"2026-08-18T18:18:30.000Z","dependencies_parsed_at":"2023-02-02T18:46:20.862Z","dependency_job_id":null,"html_url":"https://github.com/fetis/30-seconds-of-angular","commit_stats":null,"previous_names":["30-seconds/30-seconds-of-angular"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/fetis/30-seconds-of-angular","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetis%2F30-seconds-of-angular","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetis%2F30-seconds-of-angular/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetis%2F30-seconds-of-angular/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetis%2F30-seconds-of-angular/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fetis","download_url":"https://codeload.github.com/fetis/30-seconds-of-angular/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fetis%2F30-seconds-of-angular/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":341189360,"owners_count":37680851,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-08-22T15:14:58.755Z","status":"online","status_checked_at":"2026-09-25T02:00:20.896Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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"}},"created_at":"2024-03-31T14:31:30.764Z","updated_at":"2026-10-15T07:00:23.562Z","primary_language":null,"list_of_lists":false,"displayable":true,"categories":["Beginner snippets","Intermediate snippets","Advanced snippets"],"sub_categories":["Cheat Sheets and Checklists","Component State Debugging","Observables as outputs","Preseving whitespaces","Using APP_INITIALIZER to delay app start","Reusing existing custom pipes","Understanding Microsyntax","Accessing Enums in template","Default ViewEncapsulation value","hammerjs-gestures","Loader Component","ng-content","ngIf else","Optional parameters in the middle","Renaming inputs and outputs","Safe Navigation Operator","trackBy in for loops","Accessing all nested form controls","Adding keyboard shortcuts to elements","Bind to host properties with host binding","Component level providers","Global event listeners","Injecting document","Mark reactive fields as touched","Passing template as an input","Reusing code in template","Style bindings","Two-way binding any property","Window Location injection","Getting components of different types with ViewChild","Router Custom Preloading","SVG"],"readme":"[![Logo 30 Seconds of Angular](/builder/public/img/logo.png)](https://github.com/nycJSorg/30-seconds-of-angular)\n\n\n[![Build Status](https://travis-ci.com/30-seconds/30-seconds-of-angular.svg?branch=master)](https://travis-ci.com/nycJSorg/30-seconds-of-angular) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)\n\n\u003e Curated collection of useful Angular snippets that you can understand in 30 seconds or less.\n\n\n\n* Use \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eF\u003c/kbd\u003e or \u003ckbd\u003ecommand\u003c/kbd\u003e + \u003ckbd\u003eF\u003c/kbd\u003e to search for a snippet.\n* Snippets are written in Angular 8+.\n\n# 30 Seconds of Angular\n\n## Table of contents\n\nBeginner snippets\n\n* [Accessing Enums in template](#accessing-enums-in-template)\n* [Cheat Sheets and Checklists](#cheat-sheets-and-checklists)\n* [Component State Debugging](#component-state-debugging)\n* [Default ViewEncapsulation value](#default-viewencapsulation-value)\n* [hammerjs-gestures](#hammerjs-gestures)\n* [Loader Component](#loader-component)\n* [ng-content](#ng-content)\n* [ngIf else](#ngif-else)\n* [Optional parameters in the middle](#optional-parameters-in-the-middle)\n* [Renaming inputs and outputs](#renaming-inputs-and-outputs)\n* [Safe Navigation Operator](#safe-navigation-operator)\n* [trackBy in for loops](#trackby-in-for-loops)\n* [Understanding Microsyntax](#understanding-microsyntax)\n\nIntermediate snippets\n\n* [Accessing all nested form controls](#accessing-all-nested-form-controls)\n* [Adding keyboard shortcuts to elements](#adding-keyboard-shortcuts-to-elements)\n* [Bind to host properties with host binding](#bind-to-host-properties-with-host-binding)\n* [Component level providers](#component-level-providers)\n* [Global event listeners](#global-event-listeners)\n* [Injecting document](#injecting-document)\n* [Mark reactive fields as touched](#mark-reactive-fields-as-touched)\n* [Observables as outputs](#observables-as-outputs)\n* [Passing template as an input](#passing-template-as-an-input)\n* [Preseving whitespaces](#preseving-whitespaces)\n* [Reusing code in template](#reusing-code-in-template)\n* [Reusing existing custom pipes](#reusing-existing-custom-pipes)\n* [Style bindings](#style-bindings)\n* [Two-way binding any property](#two-way-binding-any-property)\n* [Using APP_INITIALIZER to delay app start](#using-app_initializer-to-delay-app-start)\n* [Window Location injection](#window-location-injection)\n\nAdvanced snippets\n\n* [Getting components of different types with ViewChild](#getting-components-of-different-types-with-viewchild)\n* [Router Custom Preloading](#router-custom-preloading)\n* [SVG](#svg)\n\n\n\n## Beginner snippets\n\n### Accessing Enums in template\nEnums are great but they are not visible in Angular templates by default. \nWith this little trick you can make them accessible.\n\n```typescript\nenum Animals {\n  DOG,\n  CAT,\n  DOLPHIN\n}\n\n@Component({\n  ...\n})\nexport class AppComponent {\n  animalsEnum: typeof Animals = Animals;\n}\n```\n\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/accessing-enums-in-template) | [⬆ Back to top](#table-of-contents) | tags: [enums](https://30.codelab.fun/tags/enums) [templates](https://30.codelab.fun/tags/templates) \n\u003cbr\u003e\u003cbr\u003e\n### Cheat Sheets and Checklists\nCheck out [Angular Cheat Sheet](https://angular.io/guide/cheatsheet) or ([alternative version](https://malcoded.com/angular-cheat-sheet)) containing lots of useful information condensed in one place. \n \nAlso [Angular Checklist](https://angular-checklist.io) contains is curated list of common mistakes made when developing Angular applications.\n\n\n#### Links\nhttps://malcoded.com/angular-cheat-sheet/,https://angular.io/guide/cheatsheet,https://angular.io/guide/styleguide\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/cheat-sheets-and-checklists) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) [cheat sheet](https://30.codelab.fun/tags/cheat-sheet) \n\u003cbr\u003e\u003cbr\u003e\n### Component State Debugging\nDebug the component state in the browser console by running:\n```typescript\nng.probe($0).componentInstance\n```\n\n\u003e `$0` - is the DOM node currently selected in dev tools (`$1` for the previous one and so on).\n\n\u003cdetails\u003e\n\u003csummary\u003eBonus\u003c/summary\u003e\n\nWith Ivy renderer engine:\n```typescript\nng.getComponent($0)\n```\n\u003c/details\u003e\n\n#### Links\nhttps://blog.angularindepth.com/everything-you-need-to-know-about-debugging-angular-applications-d308ed8a51b4\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/component-state-debugging) | [⬆ Back to top](#table-of-contents) | tags: [good-to-know](https://30.codelab.fun/tags/good-to-know) [tips](https://30.codelab.fun/tags/tips) \n\u003cbr\u003e\u003cbr\u003e\n### Default ViewEncapsulation value\nIf you're using `ViewEncapsulation` value which is different than default, it might be daunting to set the value manually for every component. \n\nLuckily you can configure it globally when bootstrapping your app:\n\n```TypeScript\nplatformBrowserDynamic().bootstrapModule(AppModule, [\n  {\n    // NOTE: Use ViewEncapsulation.None only if you know what you're doing.\n    defaultEncapsulation: ViewEncapsulation.None\n  }\n]);\n```\n\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/default-viewencapsulation-value) | [⬆ Back to top](#table-of-contents) | tags: [configuration](https://30.codelab.fun/tags/configuration) [styling](https://30.codelab.fun/tags/styling) \n\u003cbr\u003e\u003cbr\u003e\n### hammerjs-gestures\nTo act upon swipes, pans, and pinhces as well as the other mobile gestures, you can use `hammerjs` with `HostListener` decorator, or an event binding,\n\n```bash\nnpm install hammerjs\n```\n\n```typescript\n@HostListener('swiperight')\npublic swiperight(): void {\n  // Run code when a user swipes to the right\n}\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eBonus\u003c/summary\u003e\n\nHere are samples on how to use all of the `hammerjs` event bindings, you can use these events with a `HostListener` as well:\n\n```HTML\n  \u003c!-- pan events --\u003e\n  \u003cdiv (pan)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (panstart)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (panmove)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (panend)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pancancel)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (panleft)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (panright)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (panup)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pandown)=\"logEvent($event)\"\u003e\u003c/div\u003e\n\n  \u003c!-- pinch events --\u003e\n  \u003cdiv (pinch)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pinchstart)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pinchmove)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pinchend)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pinchcancel)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pinchin)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pinchout)=\"logEvent($event)\"\u003e\u003c/div\u003e\n\n  \u003c!-- press events --\u003e\n  \u003cdiv (press)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (pressup)=\"logEvent($event)\"\u003e\u003c/div\u003e\n\n  \u003c!-- rotate events --\u003e\n  \u003cdiv (rotate)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (rotatestart)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (rotatemove)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (rotateend)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (rotatecancel)=\"logEvent($event)\"\u003e\u003c/div\u003e\n\n  \u003c!-- swipe events --\u003e\n  \u003cdiv (swipe)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (swipeleft)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (swiperight)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (swipeup)=\"logEvent($event)\"\u003e\u003c/div\u003e\n  \u003cdiv (swipedown)=\"logEvent($event)\"\u003e\u003c/div\u003e\n\n  \u003c!-- tap event --\u003e\n  \u003cdiv (tap)=\"logEvent($event)\"\u003e\u003c/div\u003e\n```\n\u003c/details\u003e\n\n#### Links\nhttps://github.com/angular/angular/blob/master/packages/platform-browser/src/dom/events/hammer_gestures.ts,http://hammerjs.github.io/api/#hammer.manager,https://angular.io/api/platform-browser/HammerGestureConfig\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/hammerjs-gestures) | [⬆ Back to top](#table-of-contents) | tags: [good-to-know](https://30.codelab.fun/tags/good-to-know) [tips](https://30.codelab.fun/tags/tips) [components](https://30.codelab.fun/tags/components) [gestures](https://30.codelab.fun/tags/gestures) \n\u003cbr\u003e\u003cbr\u003e\n### Loader Component\nYou can create own helper component and use it instead of `*ngIf`.\n\n```typescript\n@Component({\n  selector: 'loader',\n  template: `\n    \u003cng-content *ngIf=\"!loading else showLoader\"\u003e\u003c/ng-content\u003e\n    \u003cng-template #showLoader\u003e🕚 Wait 10 seconds!\u003c/ng-template\u003e\n  `\n})\nclass LoaderComponent {\n  @Input() loading: boolean;\n}\n```\n\nFor usage example:\n```html\n\u003cloader [loading]=\"isLoading\"\u003e🦊 🦄 🐉\u003c/loader\u003e\n```\n\n\u003e Note that the content will be eagerly evaluated, e.g. in the snippet below `destroy-the-world` will be created before the loading even starts:\n\n```html\n\u003cloader [loading]=\"isLoading\"\u003e\u003cdestroy-the-world\u003e\u003c/destroy-the-world\u003e\u003c/loader\u003e\n```\n\n\n#### Links\nhttps://medium.com/claritydesignsystem/ng-content-the-hidden-docs-96a29d70d11b,https://blog.angularindepth.com/https-medium-com-thomasburleson-animated-ghosts-bfc045a51fba\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/loader-component) | [⬆ Back to top](#table-of-contents) | tags: [tips](https://30.codelab.fun/tags/tips) [good-to-know](https://30.codelab.fun/tags/good-to-know) [components](https://30.codelab.fun/tags/components) [templates](https://30.codelab.fun/tags/templates) \n\u003cbr\u003e\u003cbr\u003e\n### ng-content\nWith `ng-content` you can pass any elements to a component. \nThis simplifies creating reusable components.\n\n```typescript\n@Component({\n  selector: 'wrapper',\n  template: `\n    \u003cdiv class=\"wrapper\"\u003e\n      \u003cng-content\u003e\u003c/ng-content\u003e\n    \u003c/div\u003e\n  `,\n})\nexport class Wrapper {}\n```\n\n```html\n\u003cwrapper\u003e\n  \u003ch1\u003eHello World!\u003c/h1\u003e\n\u003c/wrapper\u003e\n```\n\n\n#### Links\nhttps://medium.com/p/96a29d70d11b\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/ng-content) | [⬆ Back to top](#table-of-contents) | tags: [good-to-know](https://30.codelab.fun/tags/good-to-know) [tips](https://30.codelab.fun/tags/tips) [components](https://30.codelab.fun/tags/components) \n\u003cbr\u003e\u003cbr\u003e\n### ngIf else\n`*ngIf` directive also supports `else` statement.\n\n```html\n\u003cdiv *ngIf=\"isLoading; else notLoading\"\u003eloading...\u003c/div\u003e\n\n\u003cng-template #notLoading\u003enot loading\u003c/ng-template\u003e\n```\n\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/ngif-else) | [⬆ Back to top](#table-of-contents) | tags: [ngif](https://30.codelab.fun/tags/ngif) [templates](https://30.codelab.fun/tags/templates) \n\u003cbr\u003e\u003cbr\u003e\n### Optional parameters in the middle\nNavigate with matrix params:\n\nthe router will navigate to `/first;name=foo/details`\n```html\n\u003ca [routerLink]=\"['/', 'first', {name: 'foo'}, 'details']\"\u003e\n  link with params\n\u003c/a\u003e\n```\n\n\n#### Links\nhttps://stackblitz.com/edit/angular-xvy5pd\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/optional-parameters-in-the-middle) | [⬆ Back to top](#table-of-contents) | tags: [routing](https://30.codelab.fun/tags/routing) \n\u003cbr\u003e\u003cbr\u003e\n### Renaming inputs and outputs\nIn certain cases `@Input` and `@Output` properties can be named differently than the actual inputs and outputs.\n\n```html\n\u003cdiv \n  pagination \n  paginationShowFirst=\"true\"\n  (paginationPageChanged)=\"onPageChanged($event)\"\u003e\n\u003c/div\u003e\n```\n\n```typescript\n@Directive({ selector: '[pagination]'})\nclass PaginationComponent {\n  @Input('paginationShowFirst') \n  showFirst: boolean = true;\n\n  @Output('paginationPageChanged') \n  pageChanged = new EventEmitter();\n}\n```\n\u003e Note: Use this wisely, see [StyleGuide recommedation](https://angular.io/guide/styleguide#style-05-13)\n\n\n#### Links\nhttps://angular.io/guide/styleguide#style-05-13\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/renaming-inputs-and-outputs) | [⬆ Back to top](#table-of-contents) | tags: [components](https://30.codelab.fun/tags/components) [templates](https://30.codelab.fun/tags/templates) \n\u003cbr\u003e\u003cbr\u003e\n### Safe Navigation Operator\nThe [Safe Navigation Operator](https://angular.io/guide/template-syntax#the-safe-navigation-operator----and-null-property-paths) helps with preventing null-reference exceptions in component template expressions. It returns object property value if it exists or null otherwise.\n\n```html\n\u003cp\u003e I will work even if student is null or undefined: {{student?.name}} \u003c/p\u003e\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eBonus\u003c/summary\u003e\n\n```html\n{{a?.b?.c}} \n```\nUnderneath will be compiled to.\n```html\n(_co.a == null)? null: ((_co.a.b == null)? null: _co.a.b.c));\n```\n\u003c/details\u003e\n\n#### Links\nhttps://github.com/angular/angular/issues/791\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/safe-navigation-operator) | [⬆ Back to top](#table-of-contents) | tags: [object property handling](https://30.codelab.fun/tags/object-property-handling) [tips](https://30.codelab.fun/tags/tips) [good to know](https://30.codelab.fun/tags/good-to-know) \n\u003cbr\u003e\u003cbr\u003e\n### trackBy in for loops\nTo avoid the expensive operations, we can help Angular to track which items added or removed i.e. customize the default tracking algorithm by providing a trackBy option to NgForOf.\n\nSo you can provide your custom trackBy function that will return unique identifier for each iterated item. \nFor example, some key value of the item. If this key value matches the previous one, then Angular won't detect changes.\n\n**trackBy** takes a function that has _index_ and _item_ args. \n\n```typescript\n@Component({\n  selector: 'my-app',\n  template: `\n    \u003cul\u003e\n      \u003cli *ngFor=\"let item of items; trackBy: trackByFn\"\u003e{{item.id}}\u003c/li\u003e\n    \u003c/ul\u003e\n  `\n})\nexport class AppComponent { \n  trackByFn(index, item) {\n    return item.id;\n  }\n}\n```\nIf trackBy is given, Angular tracks changes by the return value of the function. \n\nNow when you change the collection, Angular can track which items have been added or removed according to the unique identifier and create/destroy only changed items.\n\n\n#### Links\nhttps://angular.io/api/common/NgForOf,https://angular.io/api/core/TrackByFunction\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/trackby-in-for-loops) | [⬆ Back to top](#table-of-contents) | tags: [good-to-know](https://30.codelab.fun/tags/good-to-know) [tips](https://30.codelab.fun/tags/tips) [components](https://30.codelab.fun/tags/components) [performance](https://30.codelab.fun/tags/performance) \n\u003cbr\u003e\u003cbr\u003e\n### Understanding Microsyntax\nUnder the hood Angular compiles structural directives into ng-template elements, e.g.:\n\n```html\n\u003c!-- This --\u003e\n\u003cdiv *ngFor=\"let item of [1,2,3]\"\u003e\n\n\u003c!-- Get expanded into this --\u003e\n\u003cng-template ngFor [ngForOf]=\"[1,2,3]\" let-item=\"$implicit\"\u003e\u003c/ng-template\u003e\n```\n\nThe value passed to *ngFor directive is written using microsyntax. You can learn about it [in the docs](https://angular.io/guide/structural-directives#microsyntax). \n\nAlso check out an [interactive tool](https://alexzuza.github.io/ng-structural-directive-expander/) that shows the expansion by [Alexey Zuev](https://twitter.com/yurzui)\n\n\n#### Links\nhttps://angular.io/guide/structural-directives#microsyntax,https://alexzuza.github.io/ng-structural-directive-expander/,https://angular.io/guide/structural-directives#inside-ngfor\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/understanding-microsyntax) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) [structural directive](https://30.codelab.fun/tags/structural-directive) [microsyntax](https://30.codelab.fun/tags/microsyntax) \n\u003cbr\u003e\u003cbr\u003e\n\n## Intermediate snippets\n\n### Accessing all nested form controls\nSometimes we need to work with every single Control is a form. Here's how it can be done: \n\n```typescript\nfunction flattenControls(form: AbstractControl): AbstractControl[] {\n  let extracted: AbstractControl[] = [ form ];\n  if (form instanceof FormArray || form instanceof FormGroup) {\n    const children = Object.values(form.controls).map(flattenControls);\n    extracted = extracted.concat(...children);\n  }\n  return extracted;\n}\n```\n\nFor examples use:\n```typescript\n// returns all dirty abstract controls\nflattenControls(form).filter((control) =\u003e control.dirty);\n\n// mark all controls as touched\nflattenControls(form).forEach((control) =\u003e \n    control.markAsTouched({ onlySelf: true }));\n```\n\n\n#### Links\nhttps://angular.io/guide/reactive-forms\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/accessing-all-nested-form-controls) | [⬆ Back to top](#table-of-contents) | tags: [reactive forms](https://30.codelab.fun/tags/reactive-forms) [tips](https://30.codelab.fun/tags/tips) [good to know](https://30.codelab.fun/tags/good-to-know) \n\u003cbr\u003e\u003cbr\u003e\n### Adding keyboard shortcuts to elements\nIt's really easy to add keyboard shortcuts in the template: \n```html\n\u003ctextarea (keydown.ctrl.enter)=\"doSomething()\"\u003e\u003c/textarea\u003e\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eBonus\u003c/summary\u003e\n\n```html\n\u003cinput (keydown.enter)=\"...\"\u003e\n\u003cinput (keydown.a)=\"...\"\u003e\n\u003cinput (keydown.esc)=\"...\"\u003e\n\u003cinput (keydown.shift.esc)=\"...\"\u003e\n\u003cinput (keydown.control)=\"...\"\u003e\n\u003cinput (keydown.alt)=\"...\"\u003e\n\u003cinput (keydown.meta)=\"...\"\u003e\n\u003cinput (keydown.9)=\"...\"\u003e\n\u003cinput (keydown.tab)=\"...\"\u003e\n\u003cinput (keydown.backspace)=\"...\"\u003e\n\u003cinput (keydown.arrowup)=\"...\"\u003e\n\u003cinput (keydown.shift.arrowdown)=\"...\"\u003e\n\u003cinput (keydown.shift.control.z)=\"...\"\u003e\n\u003cinput (keydown.f4)=\"...\"\u003e\n```\n\u003c/details\u003e\n\n#### Links\nhttps://alligator.io/angular/binding-keyup-keydown-events\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/adding-keyboard-shortcuts-to-elements) | [⬆ Back to top](#table-of-contents) | tags: [tips](https://30.codelab.fun/tags/tips) [good-to-know](https://30.codelab.fun/tags/good-to-know) \n\u003cbr\u003e\u003cbr\u003e\n### Bind to host properties with host binding\nEvery rendered angular component is wrapped in a host element (which is the same as component's selector).\n\nIt is possible to bind properties and attributes of host element using @HostBinding decorators, e.g. \n\n```typescript\nimport { Component, HostBinding } from '@angular/core';\n\n@Component({\n   selector: 'my-app', \n   template: `\n    \u003cdiv\u003eUse the input below  to select host background-color:\u003c/div\u003e\n    \u003cinput type=\"color\" [(ngModel)]=\"color\"\u003e \n  `,\n  styles: [\n    `:host { display: block; height: 100px; }`\n  ]\n})\nexport class AppComponent {\n  @HostBinding('style.background') color = '#ff9900';\n}\n```\n\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/bind-to-host-properties-with-host-binding) | [⬆ Back to top](#table-of-contents) | tags: [components](https://30.codelab.fun/tags/components) \n\u003cbr\u003e\u003cbr\u003e\n### Component level providers\nGenerally we get one service instance per the whole application. \nIt is also possible to create an instance of service per component or directive. \n\n```typescript\n@Component({\n  selector: 'provide',\n  template: '\u003cng-content\u003e\u003c/ng-content\u003e',\n  providers: [ Service ]\n})\nexport class ProvideComponent {}\n```\n\n```typescript\n@Directive({\n  selector: '[provide]',\n  providers: [ Service ]\n})\nexport class ProvideDirective {}\n```\n\n\n#### Links\nhttps://angular.io/guide/hierarchical-dependency-injection#component-level-injectors,https://stackblitz.com/edit/angular-cdk-happy-animals\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/component-level-providers) | [⬆ Back to top](#table-of-contents) | tags: [tips](https://30.codelab.fun/tags/tips) [components](https://30.codelab.fun/tags/components) [dependency-injection](https://30.codelab.fun/tags/dependency-injection) \n\u003cbr\u003e\u003cbr\u003e\n### Global event listeners\nIt is possible to add global event listeners in your Components/Directives with `HostListener`. Angular will take care of unsubscribing once your directive is destroyed.\n\n```typescript\n@Directive({\n  selector: '[rightClicker]'\n})\nexport class ShortcutsDirective {\n  @HostListener('window:keydown.ArrowRight')\n  doImportantThings() {\n    console.log('You pressed right');\n  }\n}\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eBonus\u003c/summary\u003e\n\nYou can have multiple bindings:\n\n```typescript\n@HostListener('window:keydown.ArrowRight')\n@HostListener('window:keydown.PageDown')\nnext() {\n  console.log('Next')\n}\n```\n\nYou can also pass params:\n\n```typescript\n@HostListener('window:keydown.ArrowRight', '$event.target')\nnext(target) {\n  console.log('Pressed right on this element: ' + target)\n}\n```\n\u003c/details\u003e\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/global-event-listeners) | [⬆ Back to top](#table-of-contents) | tags: [events](https://30.codelab.fun/tags/events) [components](https://30.codelab.fun/tags/components) \n\u003cbr\u003e\u003cbr\u003e\n### Injecting document\nSometimes you need to get access to global `document`. \n\nTo simplify unit-testing, Angular provides it through dependency injection:\n\n```typescript\nimport { DOCUMENT } from '@angular/common';\nimport { Inject } from '@angular/core';\n\n@Component({\n  selector: 'my-app',\n  template: `\u003ch1\u003eEdit me \u003c/h1\u003e`\n})\nexport class AppComponent {\n\n  constructor(@Inject(DOCUMENT) private document: Document) {\n    // Word with document.location, or other things here....\n  }\n}\n```\n\n\n#### Links\nhttps://angular.io/api/common/DOCUMENT\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/injecting-document) | [⬆ Back to top](#table-of-contents) | tags: [dependency injection](https://30.codelab.fun/tags/dependency-injection) \n\u003cbr\u003e\u003cbr\u003e\n### Mark reactive fields as touched\nHere is the way to notify user that there are fields with non-valid values.\n\n`markFieldsAsTouched` function FormGroup or FormArray as an argument. \n\n```typescript\nfunction markFieldsAsTouched(form: AbstractControl): void {\n  form.markAsTouched({ onlySelf: true });\n  if (form instanceof FormArray || form instanceof FormGroup) {\n    Object.values(form.controls).forEach(markFieldsAsTouched);\n  }\n}\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eBonus\u003c/summary\u003e\n\nIt's very useful to check out more general method [Accessing all nested form controls](#accessing-all-nested-form-controls) by [Thekiba](https://twitter.com/thekiba_io) to work with controls.\n\u003c/details\u003e\n\n#### Links\nhttps://angular.io/guide/reactive-forms\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/mark-reactive-fields-as-touched) | [⬆ Back to top](#table-of-contents) | tags: [reactive forms validation](https://30.codelab.fun/tags/reactive-forms-validation) [tips](https://30.codelab.fun/tags/tips) [good to know](https://30.codelab.fun/tags/good-to-know) \n\u003cbr\u003e\u003cbr\u003e\n### Observables as outputs\n`EventEmitters`  used for `@Output`'s are just Observables with an emit method. \n\nThis means that you can just use `Observable` instance instead, e.g. we can wire up FormControl value changes directly:\n\n```TypeScript\nreadonly checkbox = new FormControl();\n@Output() readonly change = this.checkbox.valueChanges;\n```\n\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/observables-as-outputs) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) [outputs](https://30.codelab.fun/tags/outputs) \n\u003cbr\u003e\u003cbr\u003e\n### Passing template as an input\nIt's possible to take a template as `@Input` for a component to customize the render\n\n\n```typescript\n@Component({\n  template: `\n    \u003cnav\u003e\n      \u003cng-container *ngTemplateOutlet=\"template\"\u003e\u003c/ng-container\u003e\n    \u003c/nav\u003e\n  `,\n})\nexport class SiteMenuComponent  {\n  @Input() template: TemplateRef\u003cany\u003e;\n}\n```\n```html\n\u003csite-menu [template]=\"menu1\"\u003e\u003c/site-menu\u003e\n\n\u003cng-template #menu1\u003e\n  \u003cdiv\u003e\u003ca href=\"#\"\u003eitem1\u003c/a\u003e\u003c/div\u003e\n  \u003cdiv\u003e\u003ca href=\"#\"\u003eitem2\u003c/a\u003e\u003c/div\u003e\n\u003c/ng-template\u003e\n```\n\u003e Note: `ng-content` should be used for most of the cases and it's simpler and more declarative.\n\u003e Only use this approach if you need extra flexibility that can't be achieved with ng-content.\n\n\n#### Links\nhttps://blog.angular-university.io/angular-ng-template-ng-container-ngtemplateoutlet\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/passing-template-as-an-input) | [⬆ Back to top](#table-of-contents) | tags: [template](https://30.codelab.fun/tags/template) \n\u003cbr\u003e\u003cbr\u003e\n### Preseving whitespaces\nBy default Angular strips all whitespaces in templates to save bytes. Generally it's safe.\n\nFor rare cases when you need to preserve spaces you can use special `ngPreserveWhitespaces` attribute:\n\n```html\n\u003cdiv ngPreserveWhitespaces\u003e\n             (___()'`;\n             /,    /`\n       jgs   \\\\\"--\\\\\n\u003c/div\u003e\n```\n\n\u003e You can also use [preserveWhitespaces](https://angular.io/api/core/Component#preserveWhitespaces) option on a component.\n\n\n#### Links\nhttps://twitter.com/mgechev/status/1108913389277839360\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/preseving-whitespaces) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) \n\u003cbr\u003e\u003cbr\u003e\n### Reusing code in template\nWhile the best way of reusing your code is creating a component, it's also possible to do it in a template.\n\nTo do this you can use `ng-template` along with `*ngTemplateOutlet` directive.\n\n```html\n\u003cp\u003e\n  \u003cng-container *ngTemplateOutlet=\"fancyGreeting\"\u003e\u003c/ng-container\u003e\n\u003c/p\u003e\n\n\u003cbutton\u003e\n  \u003cng-container *ngTemplateOutlet=\"fancyGreeting\"\u003e\u003c/ng-container\u003e    \n\u003c/button\u003e\n\n\u003cng-template #fancyGreeting\u003e\n  Hello \u003cb\u003e{{name}}!\u003c/b\u003e\n\u003c/ng-template\u003e\n```\n\n\n#### Links\nhttps://angular.io/api/common/NgTemplateOutlet,https://angular.io/guide/structural-directives#the-ng-template\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/reusing-code-in-template) | [⬆ Back to top](#table-of-contents) | tags: [templates](https://30.codelab.fun/tags/templates) \n\u003cbr\u003e\u003cbr\u003e\n### Reusing existing custom pipes\nIf you need a custom `pipe`, before creating one, consider checking out the [NGX Pipes package](https://github.com/danrevah/ngx-pipes) which has 70+ already implemeted custom pipes.\n\nHere are some examples:\n\n```html\n\u003cp\u003e{{ date | timeAgo }}\u003c/p\u003e \n\u003c!-- Output: \"last week\" --\u003e\n\n\u003cp\u003e{{ 'foo bar' | ucfirst }}\u003c/p\u003e\n\u003c!-- Output: \"Foo bar\" --\u003e\n\n\u003cp\u003e3 {{ 'Painting' | makePluralString: 3 }}\u003c/p\u003e\n\u003c!-- Output: \"3 Paintings\" --\u003e\n\n\u003cp\u003e{{ [1, 2, 3, 1, 2, 3] | max }}\u003c/p\u003e\n\u003c!-- Output: \"3\" --\u003e\n```\n\n\n#### Links\nhttps://github.com/danrevah/ngx-pipes\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/reusing-existing-custom-pipes) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) [pipes](https://30.codelab.fun/tags/pipes) [library](https://30.codelab.fun/tags/library) \n\u003cbr\u003e\u003cbr\u003e\n### Style bindings\nYou can use advanced property bindings to set specific style values based on component property values: \n\n```html\n\u003cp [style.background-color]=\"'green'\"\u003e\n  I am in green background\n\u003c/p\u003e\n\n\u003cp [style.font-size.px]=\"isImportant ? '30' : '16'\"\u003e\n  May be important text.\n\u003c/p\u003e\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eBonus\u003c/summary\u003e\n\n```html\n\u003c!-- Width in pixels --\u003e\n\u003cdiv [style.width.px]=\"pxWidth\"\u003e\u003c/div\u003e\n\n\u003c!-- Font size in percentage relative to the parent --\u003e\n\u003cdiv [style.font-size.%]=\"percentageSize\"\u003e...\u003c/div\u003e\n\n\u003c!-- Height relative to the viewport height --\u003e\n\u003cdiv [style.height.vh]=\"vwHeight\"\u003e\u003c/div\u003e\n```\n\u003c/details\u003e\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/style-bindings) | [⬆ Back to top](#table-of-contents) | tags: [styles](https://30.codelab.fun/tags/styles) \n\u003cbr\u003e\u003cbr\u003e\n### Two-way binding any property\nSimilar to how you can two-way bind `[(ngModel)]` you can two-way bind custom property on a component, for example `[(value)]`. To do it use appropriate Input/Output naming:\n\n```typescript\n@Component({\n  selector: 'super-input', \n  template: `...`,\n})\nexport class AppComponent {\n  @Input() value: string;\n  @Output() valueChange = new EventEmitter\u003cstring\u003e();\n}\n```\n\nThen you can use it as:\n```html\n\u003csuper-input [(value)]=\"value\"\u003e\u003c/super-input\u003e\n```\n\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/two-way-binding-any-property) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) [binding](https://30.codelab.fun/tags/binding) \n\u003cbr\u003e\u003cbr\u003e\n### Using APP_INITIALIZER to delay app start\nIt is possible to execute asynchronous task before the app start by providing a function returning promise using `APP_INITIALIZER` token.\n\n```typescript\n@NgModule({\n  providers: [\n    {\n      provide: APP_INITIALIZER,\n      useValue:  functionReturningPromise\n      multi: true\n    },\n})\nexport class AppModule {}\n\n\n```\n\n\n#### Links\nhttps://hackernoon.com/hook-into-angular-initialization-process-add41a6b7e,https://angular.io/api/core/APP_INITIALIZER\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/using-app_initializer-to-delay-app-start) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) \n\u003cbr\u003e\u003cbr\u003e\n### Window Location injection\nFor testing purposes you might want to inject `window.location` object in your component.\nYou can achieve this with custom `InjectionToken` mechanism provided by Angular.\n\n```typescript\nexport const LOCATION_TOKEN = new InjectionToken\u003cLocation\u003e('Window location object');\n\n@NgModule({\n  providers: [\n    { provide: LOCATION_TOKEN, useValue: window.location }\n  ]\n})\nexport class SharedModule {}\n\n//...\n\n@Component({\n})\nexport class AppComponent {\n  constructor(\n    @Inject(LOCATION_TOKEN) public location: Location\n  ) {}\n}\n```\n\n\n#### Links\nhttps://itnext.io/testing-browser-window-location-in-angular-application-e4e8388508ff,https://angular.io/guide/dependency-injection\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/window-location-injection) | [⬆ Back to top](#table-of-contents) | tags: [dependency-injection](https://30.codelab.fun/tags/dependency-injection) [testing](https://30.codelab.fun/tags/testing) \n\u003cbr\u003e\u003cbr\u003e\n\n## Advanced snippets\n\n### Getting components of different types with ViewChild\nIt's possible to use `@ViewChild` (also `@ViewChildren` and `@ContentChild/Children`) to query for components of different types using dependency injection. \n\nIn the example below we can use `@ViewChildren(Base)` to get instances of `Foo` and `Bar`.\n\n```typescript\nabstract class Base {}\n\n@Component({\n  selector: 'foo',\n  providers: [{ provide: Base, useExisting: Foo }]\n})\nclass Foo extends Base {}\n\n@Component({\n  selector: 'bar',\n  providers: [{ provide: Base, useExisting: Bar }]\n})\nclass Bar extends Base {}\n\n// Now we can require both types of components using Base.\n@Component({ template: `\u003cfoo\u003e\u003c/foo\u003e\u003cbar\u003e\u003c/bar\u003e` })\nclass AppComponent {\n  @ViewChildren(Base) components: QueryList\u003cBase\u003e;\n}\n```\n\n\n#### Links\nhttps://www.youtube.com/watch?v=PRRgo6F0cjs\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/getting-components-of-different-types-with-viewchild) | [⬆ Back to top](#table-of-contents) | tags: [good-to-know](https://30.codelab.fun/tags/good-to-know) [tips](https://30.codelab.fun/tags/tips) [components](https://30.codelab.fun/tags/components) [dependency-injection](https://30.codelab.fun/tags/dependency-injection) \n\u003cbr\u003e\u003cbr\u003e\n### Router Custom Preloading\nAngular allows us to control the way module preloading is handled.\n\nThere are 2 strategies provided by **@angular/router**: `PreloadAllModules` and `NoPreloading`. The latter enabled by default, only preloading lazy modules on demand.\n\nWe can override this behavior by providing custom preloading strategy: In the example below we preload all included modules if the connection is good.\n\n```typescript\nimport { Observable, of } from 'rxjs';\n\nexport class CustomPreloading implements PreloadingStrategy {\n  public preload(route: Route, load: () =\u003e Observable\u003cany\u003e): Observable\u003cany\u003e {\n    return preloadingConnection() ? load() : of(null);\n  }\n}\n\nconst routing: ModuleWithProviders = RouterModule.forRoot(routes, {\n  preloadingStrategy: CustomPreloading\n});\n```\n\u003e Note that that the example above would not be very efficient for larger apps, as it'll preload all the modules.\n\n\n#### Links\nhttps://angular.io/api/router/PreloadingStrategy,https://vsavkin.com/angular-router-preloading-modules-ba3c75e424cb,https://medium.com/@adrianfaciu/custom-preloading-strategy-for-angular-modules-b3b5c873681a,https://coryrylan.com/blog/custom-preloading-and-lazy-loading-strategies-with-angular\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/router-custom-preloading) | [⬆ Back to top](#table-of-contents) | tags: [router](https://30.codelab.fun/tags/router) \n\u003cbr\u003e\u003cbr\u003e\n### SVG\nIt is possible to use SVG tags in your Angular component, to create beautiful graphs and visualizations. There are 3 things you need to know: \n\n1. When binding an SVG attribute, use `attr`\n```html\n\u003ccircle [attr.cx]=\"x\" [attr.cy]=\"y\"\u003e\u003c/circle\u003e\n```\n\n2. When creating sub-components, use attribute and not tag selector:\n```html\n// Not: \u003cchild-component\u003e\u003c/child-component\u003e\n\u003cg child-component\u003e\u003c/g\u003e\n```\n```typescript\n@Component({selector: '[child-component]' })\n```\n\n3. When using SVG tags in sub-components use svg prefix:\n```typescript\n@Component({\n  selector: '[child-component]',\n  template: `\u003csvg:circle\u003e\u003c/svg:circle\u003e`\n})\n```\n\n\n\n\u003cbr\u003e[⭐ Interactive demo of this snippet](https://30.codelab.fun/svg) | [⬆ Back to top](#table-of-contents) | tags: [tip](https://30.codelab.fun/tags/tip) [SVG](https://30.codelab.fun/tags/svg) \n\u003cbr\u003e\u003cbr\u003e\n","projects_url":"https://awesome.ecosyste.ms/api/v1/lists/fetis%2F30-seconds-of-angular/projects"}