{"id":1690,"date":"2018-12-13T15:11:33","date_gmt":"2018-12-13T14:11:33","guid":{"rendered":"https:\/\/solidt.eu\/site\/?p=1690"},"modified":"2022-08-30T14:27:57","modified_gmt":"2022-08-30T13:27:57","slug":"angular-tricks","status":"publish","type":"post","link":"https:\/\/solidt.eu\/site\/angular-tricks\/","title":{"rendered":"Angular Tricks"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Install command-line interface<\/h2>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"sh\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">npm install -g @angular\/cli<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Generate component<\/h2>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"sh\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">ng generate component components\/{component-name}\n# generate more\nng generate --help\n\n# serve local\nng serve\n\n# run production build\nng build -c production\n\n# run tests\nng test\n\n# update angular packages\nng update\n<\/pre><\/div>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"csharp\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">\/\/ update template values from async observable or promise  in 'realtime'\r\n@Component({\r\n  selector: 'async-observable-pipe',\r\n  template: '&lt;div>Time: {{ time | async }}&lt;\/div>'\r\n})\r\nexport class AsyncObservablePipeComponent {\r\n  time = new Observable&lt;string>((observer: Observer&lt;string>) => {\r\n    setInterval(() => observer.next(new Date().toString()), 1000);\r\n  });\r\n}<\/pre><\/div>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Passive link (with preventDefault)\n&lt;a [routerLink]=\"\" (click)=\"showArticles()\">Articles&lt;\/a><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Style host element in component.less file\n:host {\n   display:block;\n   background-color:red;\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- ng-container does not render a HTML Element -->\n&lt;ng-container *ngFor=\"let item of items; let i = index\">\n  &lt;!-- ... -->\n&lt;\/ng-container><\/pre>\n\n\n\n<p>*ngFor \/ ngClass<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;div *ngFor=\"let season of seasons; let i = index\" class=\"filter-item\" [ngClass]=\"{'active': selectedValue == season.value}\">&lt;\/div><\/pre>\n\n\n\n<p>Nested (inline) content<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;!-- inside component -->\n&lt;div class=\"dialog-container\">\n    &lt;div class=\"dialog\">\n        &lt;div class=\"dialog-header\">\n            &lt;ng-content select=\"header\">&lt;\/ng-content>\n        &lt;\/div>\n        &lt;div class=\"dialog-content\">\n            &lt;ng-content select=\"content\">&lt;\/ng-content>\n        &lt;\/div>\n    &lt;\/div>\n&lt;\/div>\n\n&lt;!-- outside component -->\n&lt;app-inline-dialog>\n    &lt;header>\n&lt;!-- header content -->\n    &lt;\/header>\n    &lt;content>\n&lt;!-- content -->\n    &lt;\/content>\n&lt;\/app-inline-dialog>\n<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/Reference child component as instance:\n@ViewChild(SignatureComponent) signaturePad: SignatureComponent;<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ NgFor even \/ odd\n&lt;tr *ngFor=\"let hero of heroes; let even = even; let odd = odd\" \n    [ngClass]=\"{ odd: odd, even: even }\">\n    &lt;td>{{hero.name}}&lt;\/td>\n&lt;\/tr>\n\/\/ NgFor first \/ last\n&lt;tr *ngFor=\"let hero of heroes; let first = first; let last = last\" \n    [ngClass]=\"{ first: first, last: last }\">\n    &lt;td>{{hero.name}}&lt;\/td>\n&lt;\/tr><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Getter + setter: template code\n&lt;app-expand-button [(expanded)]=\"expanded\">&lt;\/app-expand-button><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Getter + setter: controller code\nimport { Component, OnInit, EventEmitter, Output, Input } from \"@angular\/core\";\n@Component({\n  selector: \"app-expand-button\",\n  templateUrl: \".\/expand-button.component.html\",\n  styleUrls: [\".\/expand-button.component.less\"]\n})\nexport class ExpandButtonComponent implements OnInit {\n  public _expanded: boolean;\n  @Output()\n  expandedChange: EventEmitter&lt;boolean> = new EventEmitter&lt;boolean>();\n  @Input()\n  set expanded(value: boolean) {\n    if (this._expanded === value)\n      return;\n    this._expanded = value;\n    this.expandedChange.emit(value);\n  }\n  constructor() { }\n  async ngOnInit() { }\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Reference to Html element: template\n&lt;div #myElementId>&lt;\/div>\n\/\/ Reference to Html element: controller\n@ViewChild(\"myElementId\") myElement: ElementRef;<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Prevent router outlet from flickering\n&lt;div class=\"router-container\" [hidden]=\"!o.isActivated\">\n    &lt;router-outlet #o=\"outlet\">&lt;\/router-outlet>\n&lt;\/div><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/Inject html element in constructor\nconstructor(private _element: ElementRef) {\n    console.log(this._element);\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Subscribe to router events\n    constructor(_router: Router) {\n        let prevUrl = '';\n        _router.events.subscribe(event => {\n            if (event instanceof ActivationEnd) {\n                const newUrl = _router.url;\n                const urlEquals = prevUrl === newUrl;\n                const fromChildUrl = prevUrl.indexOf(newUrl) >= 0;\n                \/\/console.log('navigate component', prevUrl, '=>', newUrl);\n                const hasChildren = event.snapshot.children.length > 0;\n                const componentName =  (event.snapshot.component as any).name;\n                if (!urlEquals &amp;&amp; !fromChildUrl &amp;&amp; !hasChildren) {\n                    \/\/console.log('activated:', componentName);\n                    this.emitter.emit(Events.componentActivated, componentName)\n                }\n                prevUrl = newUrl;\n            }\n        });\n    }<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Subscribe to window events\n    @HostListener(\"document:visibilitychange\")\n    onPageVisibilityChanged() {\n        this.emitter.emit(Events.pageVisibilityChanged, { visible: document.visibilityState === 'visible' });\n    }\n\n    @HostListener(\"window:online\")\n    @HostListener(\"window:offline\")\n    onOnlineStatusChanged() {\n        this.emitter.emit(Events.onlineStatusChanged, { online: window.navigator.onLine });\n    }<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ OnInit + OnDestroy\nexport class MyComponent extends BaseComponent implements OnInit, OnDestroy {\n    ngOnInit() {\n\n    }\n    ngOnDestroy() {\n\n    }\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Null check in template\n&lt;div>{{customer?.name}} &lt;span>#{{customer?.customerNumber}}&lt;\/span>&lt;\/div><\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Relative navigation\nthis._router.navigate(\"..\", { relativeTo: this._route });<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ Use hash for routing + force refresh same route\nRouterModule.forRoot(routes, { useHash: true, onSameUrlNavigation: \"reload\" })\n\n\/\/ otherwise route redirect to home\n { path: \"**\", redirectTo: \"\/login\" }\n\n\n\/\/ Child components: route config\n\/\/ Use child component with nested &lt;router-outlet> in parent component\n{\n        path: \"article-supply\",\n        component: ArticleSupplyComponent,\n        runGuardsAndResolvers: \"always\",\n        canActivate: [AuthGuard],\n        children: [\n            {\n                path: \"salesdisplay\",\n                component: SelectSalesDisplayComponent\n            },\n            {\n                path: \"new-salesdisplay\",\n                component: SelectSalesDisplayComponent\n            }\n        ]\n    }\n\n<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ track by function example: https:\/\/netbasal.com\/angular-2-improve-performance-with-trackby-cc147b5104e5\n\n@Component({\n  selector: 'my-app',\n  template: `\n    &lt;ul>\n      &lt;li *ngFor=\"let item of collection;trackBy: trackByFn\">{{item.id}}&lt;\/li>\n    &lt;\/ul>\n    &lt;button (click)=\"getItems()\">Refresh items&lt;\/button>\n  `,\n})\nexport class App {\n  constructor() {\n    this.collection = [{id: 1}, {id: 2}, {id: 3}];\n  }  \n  getItems() {\n    this.collection = this.getItemsFromServer();\n  }  \n  getItemsFromServer() {\n    return [{id: 1}, {id: 2}, {id: 3}, {id: 4}];\n  } \n  trackByFn(index, item) {\n    return index; \/\/ or item.id\n  }\n}<\/pre>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ DeactivateGuard for component deactivation delay for e.g. animations\n\/\/ 1. In app.module.ts add: providers: [DeactivateGuard]\n\/\/ 2. In app-routing.module.ts add: canDeactivate: [DeactivateGuard] to each route\n\/\/ 3. Implement OnDeactivate in each component\n\nimport { Injectable, Component } from \"@angular\/core\";\nimport { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from \"@angular\/router\";\nimport { Observable } from \"rxjs\";\n\n\/\/ tslint:disable-next-line: naming-convention\nexport interface OnDeactivate {\n    onDeactivate(): Promise&lt;boolean>;\n}\n\n@Injectable()\n    export class DeactivateGuard implements CanDeactivate&lt;Component> {\n    canDeactivate(component: Component, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot)\n        : Observable&lt;boolean | UrlTree> | Promise&lt;boolean | UrlTree> | boolean | UrlTree {\n        if (component &amp;&amp; (component as any).onDeactivate) {\n            const c = component as OnDeactivate;\n            return c.onDeactivate();\n        }\n        return true;\n    }\n}\n<\/pre>\n\n\n\n<p>Create a component dynamically<\/p>\n\n\n\n<p><a href=\"https:\/\/netbasal.com\/dynamically-creating-components-with-angular-a7346f4a982d\">https:\/\/netbasal.com\/dynamically-creating-components-with-angular-a7346f4a982d<\/a><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">constructor(private resolver: ComponentFactoryResolver) {}\n  createComponent(type) {\n    this.container.clear(); \n    const factory: ComponentFactory = this.resolver.resolveComponentFactory(AlertComponent);\n    this.componentRef: ComponentRef = this.container.createComponent(factory);\n  }<\/pre>\n\n\n\n<p><a href=\"https:\/\/angular.io\/guide\/dynamic-component-loader\">https:\/\/angular.io\/guide\/dynamic-component-loader<\/a><\/p>\n\n\n\n<div style=\"height: 250px; position:relative; margin-bottom: 50px;\" class=\"wp-block-simple-code-block-ace\"><pre class=\"wp-block-simple-code-block-ace\" style=\"position:absolute;top:0;right:0;bottom:0;left:0\" data-mode=\"csharp\" data-theme=\"monokai\" data-fontsize=\"14\" data-lines=\"Infinity\" data-showlines=\"true\" data-copy=\"false\">export class AdBannerComponent implements OnInit, OnDestroy {\n  @Input() ads: AdItem[] = [];\n\n  currentAdIndex = -1;\n\n  @ViewChild(AdDirective, {static: true}) adHost!: AdDirective;\n  interval: number|undefined;\n\n  ngOnInit(): void {\n    this.loadComponent();\n    this.getAds();\n  }\n\n  ngOnDestroy() {\n    clearInterval(this.interval);\n  }\n\n  loadComponent() {\n    this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;\n    const adItem = this.ads[this.currentAdIndex];\n\n    const viewContainerRef = this.adHost.viewContainerRef;\n    viewContainerRef.clear();\n\n    const componentRef = viewContainerRef.createComponent&lt;AdComponent>(adItem.component);\n    componentRef.instance.data = adItem.data;\n  }\n\n  getAds() {\n    this.interval = setInterval(() => {\n      this.loadComponent();\n    }, 3000);\n  }\n}<\/pre><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Install command-line interface Generate component *ngFor \/ ngClass Nested (inline) content Create a component dynamically https:\/\/netbasal.com\/dynamically-creating-components-with-angular-a7346f4a982d https:\/\/angular.io\/guide\/dynamic-component-loader<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":true,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1690","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/1690","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/comments?post=1690"}],"version-history":[{"count":41,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/1690\/revisions"}],"predecessor-version":[{"id":6634,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/posts\/1690\/revisions\/6634"}],"wp:attachment":[{"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/media?parent=1690"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/categories?post=1690"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/solidt.eu\/site\/wp-json\/wp\/v2\/tags?post=1690"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}