Working with Angular

Tips for if you are starting working with Angular 7
Cover Image for Working with Angular
Joey Gough
Joey Gough

Angular is full-featured, well documented and has a good community. I came to Angular after some time working with React. Prior to that I had used AngularJS to some degree but with Angular, I never used it before I got a job using it. Angular can be difficult to grasp in its enormity so here I just want to document some of the topics, subjects, and techniques that I found most useful as I developed my ability to use it.

Typescript

Typescript is a statically typed variant of Javascript. it can really shine when used in conjunction with an editor that can perform static type-checking and autocompletiong (VSCode seems to be second to none). It's usefulness becomes even more evident in larger projects with many contributors. In basic terms, Typescript defines what 'type' is returned from a method, or what 'type' an argument is, and it allows custom type definition.

// Here is a Person type
type Person {
  name: string;
  age: number;
}

// This function accepts a Person object and returns their name (a string)
function getName(person: Person): string {
  return person.name;
}

// This function takes an argument array of people and returns their combined age (a number)
function combinedAge(people: Person[]): number {
  return people.reduce(
    (accumulator, currentValue) => accumulator + currentValue
  );
}

Angular is written in Typescript. So developing with an ide that does static typechecking allows for rapid development when using Angular Libraries. This is a must. It is also good practice to avoid using the any type at all costs. If you use the any type, then the usefulness of typescript disappears from the inside out and could cause problems later on.

Dependancy Injection (DI)

Dependancy Injection is at the core of designing Angular Application Architecture. It is concerned with Injectable Service Classes and how to expose these objects in our components:

In Angular, Modules can be lazy-loaded.

providers

// Here is an Injectable Service Class
@Injectable()
export class MyInjectableService {}

// Define the root Module
// Inject the service
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  // See here
  providers: [MyInjectableService],
  exports: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

This is the same as writing:

// Here is an Injectable Service Class provided in the root
@Injectable({
  providedIn: "root"
}))
export class MyInjectableService {}

// Define the root Module - no need to provide the Service Class
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  exports: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

This makes MyInjectableService available to AppComponent by injection using Typescript notation:

@Component({ ...metaData })
export class AppComponent {
  constructor(service: MyInjectableService) {}
}

If a service is provided in a Module it is automatically provided in all of the submodules. So when the service is injected into a component, it will first check its module for the service, then check that modules parent module for it, and so on and so forth until it reaches the root module at which point it will find the Service or Throw an error.

The DI system can manage instances of these Injectable Service Classes, so singleton objects can mange global state.

components

This constitutes a huge difference between providing services and declaring components in a module; Services are automatically provided to all submodules, whereas Components must be declared in each module directly in which they will be used.

RxJS

RxJS is an expression of stream programming. Meaning that, as values change, callbacks are executed. This stream-like nature of RxJS can make it fell like a fluid and natural way of programming. RxJS provides a small colletion of Observable classes, a basic enough class being the Subject class and my most used to date being the BehaviorSubject. These classes can emit values to Observers, i.e. Observers that are subscribed to the the Observable will receive the emitted values and execute callbacks with the values as arguments.

This is particulary useful when managing highly dynamic state on a cross-component, and cross-module basis. By leveraging the power of the DI system in conjunction with RxJS, the developer can be sure that all areas of an application are being updated reliably as state changes. RxJS actually lends power to many utilities in the Angular toolkit: Take for example the SelectionModel as above. Within the object there lies an Observable named changed which can be subscibed to:

import { SelectionModel } from "@angular/cdk/collections";

@Component(...metaData)
export class AppComponent implements OnInit {
  constructor(peopleSelection: PeopleSelectionService) {}
  ngOnInit(): void {
    this.peopleSelection.selection.changed.subscribe(e => {
      console.log(`I have received a value ${e}`);
    });
  }
}

The reason that this works is that when the selection.select(value) is called, it internally triggers changed.next(value), which broadcasts the value to all observers, which are subscribed to change. This is a very powerful tool and should be incorporated in custom services wherever possible. RxJS also lies in the heart of Angulars HttpClient Module and the Reactive Forms Module

Selection Model

If you are using Angular, then you will probably find an opportunity to use the Selection Model. The Selection Model is a stellar example of where Angular's 'out-of-the-box' capabilities can really help. Angular's cdk module provides a SelectionModel typescript class. Lets say we want to track a selection of Person Objects as described before.

import { SelectionModel } from "@angular/cdk/collections";

@Component(...metaData)
export class SelectionExample {
  peopleSelection = new SelectionModel() < Person > true /* multiple */;

  select(person: Person): void {
    this.peopleSelection.select(person);
    return;
  }

  checkIfSelected(person: Person): boolean {
    return this.peopleSelection.select(person);
  }
}

Obviosuly that code is slightly over-written, but you get the idea.

Forms

Forms are amongst the most prevalent aspects of functional websites and Angular provides an Injectable Service for managing forms and their state named FormBuilder. This service is incredably well-inegrated with DOM UI elements so that it can respond reactively with touches and changes perform by a user. It allows for validation and cross validation of input values. Using the forms module can prevent some challenges in that the form is a complex object and building custom reusable componentes requires two-way data-binding, a centralised service or an implementation of ControlValueAccessor. The problem is that Angular Components are so well compartmentalised, that homogenising the complex object of the Angular cdk betwen component can be a challenge.

Summary

I hope this helps if you are about to take on an Angular Project.