Angular development (1/4)

This article consists of notes on Angular Basics, Debugging, Components, Data Binding, Directives, Services, Dependency Injection and Routing taken while doing the course Angular – The Complete Guide (2020 Edition) from Maximilian Schwarzmüller. I do want to do at least three more articles any time in the future covering the following respective aspects

  1. Observables, Forms, Pipes, HTTP Requests and Authentication.
  2. Dynamic Components, Angular Modules, Deployment, NgRX and Angular Universal.
  3. Angular Animations, Offline Capabilities, Unit Testing and Typescript.

Without further ado,

. Emmet in Visual Studio Code (https://code.visualstudio.com/docs/editor/emmet)

. You can basically bind to all Properties and Events – a good idea is to console.log() the element you’re interested in to see which properties and events it offers. Important – for events, you don’t bind to onclick but only to click (=> (click)). That’s event binding (and it adds a click listener).

. For Two-Way-Binding to work, you need to enable the ngModel directive. This is done by adding the FormsModule to the imports[]  array in the AppModule. You then also need to add the import from @angular/forms in the app.module.ts file:

import { FormsModule } from '@angular/forms';

Then [(ngModel)].

. Structural directives are the ones that change the DOM (elements get added / removed). They need to have asterisk *. For instances, *ngIf and *ngFor. Attribute directives (change only the element they are added to – like the color) use property binding. So, they have squared brackets []. For instance,  [ngStyle] and [ngClass] because we need to pass a Javascript object configuring our styles, when we want to attach each style. Note that we can’t have more than one structural directive in the same element.

. Extract the index of *ngFor. For instance,

<div *ngFor="let logItem of logs; let i = index" [ngStyle]="{background-color: i >= 4? 'blue' : 'transparent'}" [ngClass]={'white-text': i>= 4}">

. Prevent creation of testing file when creating component changed from --spec false to --skipTests true.

. For debugging using Chrome Sourcemaps… In developer mode, webpack, . folder and you’ll find your Typescript components where you can add specific breakpoints for instances.

. We can also use Angular Augury (https://augury.rangle.io/) which can be used to check out the State of properties, an Injector graph to see the dependencies between components and services.

. To pass data between components, HTML elements and directives, we use property and event binding.

. Whichever styles we define in one component doesn’t go to the other due to View Encapsulation. That’s not a default CSS behaviour but Angular enforcement. By default it’s set to Emulated but can be changed to None.

. Local references can be very handy. Simply add to any HTML element #nameOfReference.

. In Angular 8+, the @ViewChild() syntax which changed slightly. Instead of:

@ViewChild('serverContentInput') serverContentInput: ElementRef;

use

@ViewChild('serverContentInput', {static: true}) serverContentInput: ElementRef;

The same change (add { static: true } as a second argument) needs to be applied to ALL usages of @ViewChild() (and also @ContentChild()) IF you plan on accessing the selected element inside of ngOnInit(). If you DON’T access the selected element in ngOnInit (but anywhere else in your component), set static: false instead! If you’re using Angular 9, you only need to add { static: true } (if needed) but not { static: false }.

. In @ViewChild, we need to use nativeElement to get access to the element and nativeElement.value for its value.

. If you want to add content in between a selector (app-controller-name), go to the template and add <ng-content> or else that content will be lost.

. Mediator pattern. From outside in (parent to child) use the decorator @Input. From inside out (child to parent) use @Output. $event gives us access to the event data and that’s used in the parent. In the child use EventEmitter.

. Handy info on communication between components – https://stackoverflow.com/a/62755322/5675325

. Angular Renderer class is a better approach for DOM access. For instance, to change the style of a HTML element. We should use the Renderer for any DOM manipulations. More about Renderer methods here (https://angular.io/api/core/Renderer2)

. @HostListener to react to any events. For instance, mouseleave or mouseenter

. @HostBinding can be used to bind to any property

. Camelcase is important when accessing a DOM property which doesn’t know dashes

. [defaultColor]=”‘yellow'” can be changed to defaultColor=”yellow” (so property binding without square brackets as long as we also omit the single quotation marks between the double quotation marks)

. A Service is just a normal Typescript class. If you want to use it in a child component and you already injected the service to the parent, then you won’t want to write it in the providers of the child or else you’ll end up with two instances of that Service (Hierarchical injector).

. If you want to inject Service A into Service B, add metadata with the decorator @Injectable() to Service B.

. Using Services for Cross-Component Communication. Add an EventEmitter to the Service, emit() in the one where the information comes from and in the subscribe to the one receiving the info.

. If you’re using Angular 6+ (check your package.json to find out), you can provide application-wide services in a different way. Instead of adding a service class to the providers[] array in AppModule, you can set the following config in @Injectable():

   @Injectable({providedIn: 'root'})

   export class MyService { ... }

This is exactly the same as:

   export class MyService { ... }

and

   import { MyService } from './path/to/my.service';

   @NgModule({ ... providers: [MyService] })  

   export class AppModule { ... }

Using this new syntax is completely optional, the traditional syntax (using providers[] ) will still work. The “new syntax” does offer one advantage though: Services can be loaded lazily by Angular (behind the scenes) and redundant code can be removed automatically. This can lead to a better performance and loading speed – though this really only kicks in for bigger services and apps in general.

. Good practice to do initialization in the ngOnInit().

. To not access the original array stored in the service when getting jobs, create a method getJobs() { return this.jobs.slice() } to get a copy. If you do that, you might need an EventEmitter in the jobsService and subscribe to it in the jobs-list component.

. Setting up and loading router. In the template use router-outlet. In app.module add Routes {path:'users',component:'UserComponent'} and in imports Router.forRoot().

. For navigation, href refreshes the page at any request. Instead, use routerLink. Can be used two ways, [routerLink]="['/users']" or routerLink="/users".

. State is just data / information from your app.

Related Stories