Requesting “lookup” data from an API in Angular can quickly weigh your application down if you’re having to grab the same data over and over. The type of lookup data I’m talking about is say fixed country lists, or a set of user roles, or any other set of data that is rarely going to change on a daily, weekly, or even monthly basis.

I recently tried to solve this by implementing a level of caching in the Angular app that was purely in memory. I figured that if I cache everything in memory, then a simple refresh of the page “clears” the cache, but requests to grab any lookup data on multiple pages won’t result in multiple calls to my API. I also figured it was going to be the easiest way to approach things.

Avoiding Interceptors

There’s a tendency in Angular that when you are dealing with anything HTTP request related, you create an interceptor for it. I’ve been guilty of this in the past for sure! But the problem with Interceptors is that it’s a bit of an all or nothing approach. Opting out of interceptors is not that easy, and “configuring” when an interceptor runs and when it doesn’t is also a bit of a black box. For example, someone looking at a piece of that looks like so :

this.http.get(`myAPI.com`);

Does this cache your request? Does it run any interceptors at all? It’s hard to say without really digging into the code.

And don’t get me wrong, I do use interceptors a lot. But generally speaking, I try and make it so that in the overwhelming majority of cases, I want the interceptor to run. In our case, we only want to run the caching interceptor on a few select endpoints.

CachedHttpClient Service

Instead what I did is I created a CachedHttpClient that functions more or less like your regular HTTP service you already have in Angular.

The code :

import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

@Injectable({
    providedIn: 'root'
})
export class CachedHttpClient
{
    cachedItems : any[] = [];

    constructor(private http : HttpClient) { 

    }

    getCached<T>(url : string) : Observable<T> {
        if(this.cachedItems[url])
        {
            return of(this.cachedItems[url] as T);
        }

        return this.http.get<T>(url).pipe(map((item : T) => {
            this.cachedItems[url] = item;
            return item;
        }));
    }
}

All this does is before running your HTTP call, we check if the exact URL is in the cache (This includes query strings also), and if not, run the http call, add the item to the cache, and then return the result. On the next request, it’s going to hit the cache and not have to make the http call!

We can inject it into a service like so :

export class MyService {
  constructor(private http : HttpClient, private cachedHttp : CachedHttpClient) { 
  }

  getLookupData() {
    return this.cachedHttp.getCached<LookupData>(`myAPI/LookupData`);
  }
}

Notice that it’s extremely easy to see what’s cached and what’s not. Not only are we using a class called CachedHttpClient, but the actual method call is “getCached”. There’s no hidden magic going on for a developer to shoot themselves in the foot.

Limitations

It is worth pointing out a few limitations.

If a user refreshes their browser (Or closes their browser), then the cache is lost. In my case, this is acceptable because I only really want to cache values as users move through the site. I don’t mind that when they do a hard refresh the first few pages have to fetch those values again and re-cache them. Infact, I somewhat like the fact that a user doesn’t have to know any “tricks” on clearing their “browser cache”, they just have to refresh.

And finally, the above code does not really handle race conditions all too well (e.g. If on a page, two components request the same lookup data). To me again, this was acceptable. Introducing some sort of lock mechanism was really overkill and in 99% of cases, you aren’t going to run into an issue where on one page, you request the same data at exactly the same time (Or you shouldn’t anyway!).

If you’re a C# developer moving to javascript, one of the very first things you’ll miss is the ability to write Linq on lists. While Javascript has a couple of methods to deal with arrays, some of them don’t quite match up to the power of Linq. Luckily, there is a great javascript library called Lodash which has almost everything you need! If you are interested in adding Lodash to your Angular project, you can read our guide here :¬†https://tutorialsforangular.com/2020/08/02/using-lodash-with-angular/

I’m going to do this page cheatsheet style and simply list out the Linq method with it’s Lodash equivalent. Feel free to bookmark this page and come back to it when you start scratching your head thinking “I know how to do this in C#…” as quite often, it’s just a simple rename of your method and you are good to go.

My Models

For the sake of simplicity, the model I will be using will look like so :

{
    people : [
        {
            "firstName" : "John"
            "lastName" : "Smith"
            "age" : 30
        }
    ]
}

Lodash / C# Linq Cheatsheet

All

//C#
items.All(x => x.Age == 30);
//Lodash
_.every(items, x => x.age === 30);
OR
_.every(items, {'age': 30});

Any

//C#
items.Any(x => x.Age == 30);
//Lodash
_.some(items, x => x.age === 30);
OR
_.some(items, {'age': 30});

Average

//C#
items.Average(x => x.Age == 30);
//Lodash
_.meanBy(items, x => x.age === 30);
OR
_.meanBy(items, 'age');

Contains

//C#
items.Contains(myItem);
//Lodash
_.includes(items, myItem);

Count

Count how many match a predicate, not just the length of the array. Note that the return object for Lodash is essentially a group by on the predicate. For example with a collection with two items, one with an age of 30 and the other of an age of 31. The result is :

{
  false: 1,
  true: 1
}
//C#
items.Count(x => x.Age == 30);
//Lodash
_.countBy(items, x => x.age === 30);
OR
_.countBy(items, {'age' : 30});

Distinct

Note that in different versions of Lodash, the functions unique, uniq, and uniqBy have all been swapped around so you may need to try a variant of those depending on your lodash version.

//C#
items.Distinct(x => x.FirstName);
//Lodash
_.unique(items, x => x.firstName);
OR
_.unique(items, 'firstName')

First / FirstOrDefault

Lodash doesn’t provide functionality to either throw an exception like the C# First, or to return null like FirstOrDefault. Instead it will always return an empty array ([])

//C#
items.First(x => x.Age == 30);
//Lodash
_.first(items, x => x.age === 30);
OR
_.first(items, {'age': 30})

Foreach

//C#
items.ForEach(x => x.Age = 30);
//Lodash
_.forEach(items, x => x.age = 30);

Last / LastOrDefault

Similar to First / FirstOrDefault, Lodash doesn’t provide functionality to either throw an exception like the C# Last, or to return null like LastOrDefault. Instead it will always return an empty array ([])

//C#
items.Last(x => x.Age == 30);
//Lodash
_.last(items, x => x.age === 30);
OR
_.last(items, {'age': 30})

Max

Max in C# linq returns only the value of the property (e.g. If the max age is 30, it will return the value 30, not the actual array item). Lodash however will return the entire item that has the highest property value. If you want the entire item in C#, you have to use OrderBy/OrderByDescending.

//C#
items.Max(x => x.Age);
//Lodash
_.max(items, x => x.age);
OR
_.max(items, 'age'})

Min

Similar to Max, C# will return only the property while Lodash will return the entire item.

//C#
items.Min(x => x.Age);
//Lodash
_.min(items, x => x.age);
OR
_.min(items, 'age'})

OrderBy / OrderByDescending

Some versions of Linq only support sortBy which only sorts in ascending value. Similar to C#, orderby is stable, that is, the original order of the items is kept in tact and you must read the resulting object.

//C#
var sortedItems = items.OrderBy(x => x.Age);
OR
var sortedItems = items.OrderByDescending(x => x.Age);
//Lodash
var sortedItems = _.orderBy(items, ['age']);
OR
var sortedItems = _.orderBy(items,['age'], ['desc']);

Select

//C#
items.Select(x => x.FirstName);
//Lodash
_.map(items, x => x.firstName)

Skip

//C#
items.Skip(10);
//Lodash
_.slice(items, 10)

Sum

//C#
items.Sum(x => x.Age);
//Lodash
_.sumBy(items, x => x.age);
OR
_.sumBy(items, 'age');

Take

//C#
items.Take(10);
//Lodash
_.slice(items, 0, 10)

Where

//C#
items.Where(x => x.Age == 30)
//Lodash
_.filter(items, x => x.age === 30);

One painful thing when working with Angular is getting used to Observables vs Promises, and how some libraries use one or the other exclusively. It can be incredibly frustrating to add a library only to find it wants to force you into using promises, when the rest of your project uses observables.

But why would you use one or the other? Well…

You generally use an Observable if :

  • You are building something entirely for Angular as most of Angular uses Observables, it’s nice to keep to the same script.
  • You need to output more than one value over time/stream data, observables allow you to output multiple values while a promise can only output one.
  • You want to use RxJS operators such as map, tap etc.

You generally use a Promise if :

  • You are only ever going to return a single value
  • You prefer the “await” construct over using “then” or “subscribe”

In will get a feel over time as to which one you will need to use, but if you are using Angular, then chances are you will be sticking with Observables.

The real challenge comes when you have a library that will only return promises/observables, and your code is written completely the other way. Well never fear!

Turning Promises Into Observables

Converting a promise into an observable is rather easy with the “from” operator.

First, import “from” from the rxjs library :

import { from } from 'rxjs';

Then it’s as easy as :

from(myService.myPromiseMethod()).subscribe(x => console.log(x));

Be very careful that you use the “from” operator and not “of”. For example :

of(myService.myPromiseMethod())

This will return an observable but the value will be the promise itself, not the returned value of the promise. of is a really useful operator to return synchronous values inside your code, but should not be used for “unwrapping” promises.

Turning Observables Into Promises

If you thought going from a promise to an observable was easy, converting an observable into a promise is actually extremely easy with the “toPromise()” method available on every observable.

let myValue = await myService.getAll().toPromise();

There really isn’t much magic to it at all!

On almost every single Angular project after a certain size, you’ll start running into these errors :

An unhandled exception occurred: Call retries were exceeded

Or

JavaScript heap out of memory

Both of these point to the same issue. That your build process is hitting memory limits and simply crashing. It can be frustrating to debug for a few reasons.

  • Memory limits can be set for all NodeJS processes on a machine, meaning that what will build on one developers machine may not build on another because they may have already upped/lowered their memory limits.
  • Similar to the above, certain hosted build agents (e.g. Azure Devops, Github Actions etc), may have memory limits set lower/higher than you might think, meaning that builds succeed/fail here when they wouldn’t otherwise on other machines.
  • Non production builds of your angular project (e.g. Just using ng serve) build fine, but building with the production flag consumes far more memory, and so may crash only when building in production.

Luckily there is a really easy fix that gets around all of the above. While you can leave a note in the readme saying “Hey, you need to up your memory to XYZ”, a better option is to create a npm build script that sets the memory limit for that build only, and leaves everything else on the machine as is.

For example, a recent project of mine has these sets of scripts in the package.json :

"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e",
  "build-prod": "node --max_old_space_size=8000 ./node_modules/@angular/cli/bin/ng build --prod",
}

Notice the last script. It looks complicated but it’s actually quite simple.

  • Start the Node process.
  • Set the “max old space size” to 8000MB.
  • Find the angular CLI in your node modules folder.
  • Run an angular build of production.

Now anytime we need to build for production, we only need to run “npm run build-prod”, including on our build servers.

As to what you should set your memory limit to. You should try and set it relatively high, but not enough to consume all of your memory on your machine. By default, depending on your installed version of node, the default is between 500MB to 1GB. So even allowing up to 2 or 4GB should be enough to build most Angular projects.

Moving between projects that use NPM and Yarn typically isn’t a big deal. For the most part, the package dependency managers work almost identical. But one thing that does tend to trip developers up is the subtle command line changes between the two. Often it’s just the case of swapping install/uninstall in NPM to add/remove in Yarn, so here’s a quick cheatsheet for doing just that.

NPM CommandYarn CommandDescription
npm install [package-name]yarn add [package-name]Installs a package
npm install [package-name] –save-devyarn add [package-name] –devInstalls a package as a dev dependency
npm installyarn OR yarn installInstalls all dependencies inside package.json
npm uninstall [package-name]yarn remove [package-name]Uninstalls a package
npm uninstall [package-name] –save-devyarn remove [package-name]Uninstalls a package as a dev dependency (Yarn command is the same as uninstall regular dependency)
npm updateyarn upgradeUpdates all packages
npm update [package-name]yarn upgrade [package-name]Updates a single package
npm install [package-name] -gyarn global add [package-name]Installs a globally accessibly package
npm uninstall [package-name] -gyarn global remove [package-name]Uninstalls a globally accessibly package

While the above are the main commands that have subtle differences. There are actually some commands that are identical between NPM and Yarn, that you basically just sub out the word npm with yarn on the command line and you are good to go. These are :

NPM CommandYarn CommandDescription
npm install –productionyarn install –productionInstalls all dependencies in package.json *except* dev dependencies
npm inityarn initCreates a new package.json file / project setup
npm runyarn runRuns scripts from your package.json file
npm testyarn testRuns tests from your package.json file
npm publishyarn publishPublishes your package/td>
npm cache cleanyarn cache cleanClears the global package cache
npm loginyarn loginLogs a user into an package register

Importing Lodash into your Angular project may be slightly controversial in some circles, but I often find myself adding it (and adding the few KB that comes along with it), rather than reinventing the wheel in each project. If you’ve never used it before, Lodash is a javascript library that provides handy data manipulation extension methods for arrays/collections. If you’ve used C# LINQ, you’ll probably be familiar with many of the methods like OrderBy, GroupBy, Join etc. It’s also important to note that it pays to check if the default Array type in Javascript has what you need as there is a little bit of overlap (For example Find exists on both an array and Lodash).

But that’s not all! One of the most common use cases for Lodash is actually manipulating objects that aren’t arrays. For example, an extremely common use-case for me is using the _.clone() method which copies all the values of an object into a new object that’s safe for editing. This is extremely common for me when I’m doing two way data binding on a form that a user can “cancel”, so I still have the original object in tact.

In anycase, this post isn’t a pros and cons guide to using Lodash, it’s about adding it to your Angular project, so let’s get on and do that!

Adding Lodash To Angular

The first thing you want to do is add the Lodash package to your project using NPM/Yarn.

NPM

npm i lodash --save

Yarn

yarn add lodash

This adds Lodash to our project and at this point is ready for use, but it’s just the raw library. What we also need is the type definitions to give us some nice strongly typed defintions inside Typescript. For that we need to install one more package.

NPM

npm i --save-dev @types/lodash

Yarn

yarn add @types/lodash --dev

Note that we only add the type definitions as a dev dependency as it is not required at runtime, only while you are developing your project.

Anywhere in your project, you should now be able to import Lodash like so :

import * as _ from 'lodash';

let myItem = {};
let clonedItem = _.clone(myItem);

If you’re coming from a language such as Java or C#, the concept of constructor overloading is a pretty common one. But as a refresher in say C#, we can overload constructors like so :

class MyClass
{
	public MyClass(string value)
	{
		this.value = value;
	}
	
	public MyClass(int value)
	{
		this.value = value.toString();
	}

	private string value;
}

Whereby we create two different constructors, that take two very different parameters, to construct our object. It should also note that in C#, there is no limitation on how different these constructors can be. For example you can even have a different number of parameters :

class MyClass
{
	public MyClass(string value)
	{
		this.value = value;
	}
	
	public MyClass(string first, string second)
	{
		this.value = first + second;
	}

	private string value;
}

In Typescript/Angular, things aren’t so easy. If we tried the above code in Typescript such as :

export class MyClass
{
	constructor(value : string)
	{
		this.value = value;
	}
	
	constructor(value : number)
	{
		this.value = value.toString();
	}

	private value : string;
}

You will get the following error :

Module parse failed: Duplicate constructor in the same class 

You’ll probably also see something like :

error TS2392: Multiple constructor implementations are not allowed.

But you’ve heard that Typescript *does* support constructor overloading, so what gives? Why doesn’t this work.

Overloading Constructors In Typescript

Overloading in Typescript is a little different to what you might expect, while you can overload constructors, you cannot have multiple implementations. What this means in practice is that you either can create a union type such as :

export class MyClass
{
	constructor(value : string | number)
	{
		this.value = value.toString();
	}

	private value : string;
}

Where the constructor can accept one of either types, and you handle both within the same implementation. In this example we can handle both easily because calling toString() on a string is a safe operation, but otherwise you have to resort to using typeof checks :

export class MyClass
{
	constructor(value : string | number)
	{
		if(typeof value === "string")
		{
			this.value = value;
		}

		if(typeof value === "number")
		{
			this.value = value.toString();
		}
	}

	private value : string;
}

Honestly for me, this just looks like a mess and is hardly worth the hassle.

It get worse (just in my opinion), when you want a differing amount of parameters for two different constructors. What you need to instead do is create a single implementation that each constructor can “fall down” to the next without breaking. For example :

export class MyClass
{
    constructor(value : string)
    constructor(first : string, second? : string)
    {
        if(!second)
        {
            this.value = first;
        }else 
        {
            this.value = first + second;
        }
    }

    private value : string;
}

The constructor with a single “value” is able to fall down to the second constructor because the second parameter is nullable. We can determine which constructor was used by checking if the second value is set or not.

Again, less than ideal. I find the biggest issue is as you add constructors, removing one in the “middle” of the list suddenly breaks everything. In my opinion, this way of overloading constructors in typescript is extremely brittle and prone to giving developers headaches.

A Better Way With Static Factories

Because of the way constructor overloading works, it can be hard to wrangle if you have wildly different constructor implementations depending on the parameters. For this reason I use a simple  static factory pattern.

export class MyClass
{
    static fromSingleValue(value : string) : MyClass {
        var result = new MyClass();
        result.value = value;
        return result;
    }

    static fromTwoValues(first : string, second : string) : MyClass {
        var result = new MyClass();
        result.value = first + second;
        return result;
    }

    private value : string;
}

Now I can just call MyClass.fromSingleValue(‘something’) to get a class constructed for me. Better yet, any developer looking at this will find it extremely easy to follow, even if they’ve never used Typescript before.

Where static factories really come into their own is when you are consuming an entire other object :

export class MyOtherClass
{
    public value : string;
}

export class MyClass
{
    static fromSingleValue(value : string) : MyClass {
        var result = new MyClass();
        result.value = value;
        return result;
    }

    static fromTwoValues(first : string, second : string) : MyClass {
        var result = new MyClass();
        result.value = first + second;
        return result;
    }

    static fromMyOtherClass(myOtherClass : MyOtherClass) : MyClass {
        var result = new MyClass();
        result.value = myOtherClass.value;
        return result;
    }

    private value : string;
}

Now adding and removing constructors does not break any other constructor, and they all act independently from one another.

Detecting clicks on a particular component/element that you have complete control over is fairly trivial in Angular, but what about if you want to know when a user clicks somewhere on the page on something that is *not* inside a particular component. It may sound like a weird edgecase but it’s actually really common when building things like custom popup modals or even just custom dropdown/select controls. With these you often want to detect if a user clicks away from the component so that you can hide the modal/popup or slide up the dropdown control.

I couldn’t find anything really talking about this particular issue but as it turns out, it’s pretty easy to get up and running!

Let’s assume I have a component called “DropDownComponent” that I want to detect if there are clicks *outside* of this control. Basically if there is a click anywhere else on the webpage. The first thing we have to do, is inject a reference to ourselves in the constructor.

constructor(private elementRef: ElementRef) {
}

When ElementRef is injected this way, Angular injects in the HTML native element that this component is drawn into, which is perfect for us because now we know in plain javascript/html, what our element is referenced as.

The next piece of the puzzle is actually very trivial. Inside our component we add a HostListener that listens for any document:click.

@HostListener('document:click', ['$event.target'])
public onPageClick(targetElement) {
  const clickedInside = this.elementRef.nativeElement.contains(targetElement);
  if (!clickedInside) {
	//Do something. 
  }
}

The code itself is pretty self explanatory. We detect any document clicks (Which is a click anywhere on the page), and in doing so, we detect exactly what element was clicked. Next we determine if the element that was clicked lives inside our component by using the injected ElementRef we put in the constructor, if it doesn’t, then bingo, we know that the user has clicked outside of the component and we can run whatever custom code we wish to (e.g. Close the modal, slide up the dropdown list etc).

This probably looks a little heavy handed (And it is really… ), but a good thing to note is that HostListeners are destroyed when the component they belong to is destroyed. So unless you attach this to every single component, you’ll generally only have 1 or 2 of these document click listeners running at any one time.

I was working with a piece of code recently that made liberal use of the “Tap” operator on an observable. I’ve seen it used pretty often, but everytime I try and find documentation to show a junior developer how it works, I always find it a really overcomplicated mess. Tap, infact, is a really simple operator on the surface that you really shouldn’t have a hard time understanding.

Let’s jump straight into some code. The most common use-case for using tap is because you want to use the result of an observable elsewhere, but still pass the exact same result back to any subscriber.

For instance let’s say that I want to call an API to fetch the current user, and I want to do nothing more than log that user to the console, and then return that same user out. A very naive way to achieve this would be :

this.http.get<User>('api/user').pipe(map((user : User) => {
	console.log(`Current User Is : ${user.name}`)
	return user;
}));

Theoretically not a heck of a lot wrong with this, I mean it works, but it’s not nice. You are calling the map function purely so that you can log the user, but then you aren’t actually mapping anything, and instead returning the same user. The result of this function is still Observable<User> so the caller doesn’t know what’s going on behind the scenes, but it’s messy.

One of the worst ways I’ve seen someone try and achieve this looked like so :

return Observable.create((observer: Observer<User>) => this.http.get<User>('api/user').subscribe((user : User) => {
	console.log(`Current User Is : ${user.name}`)
	observer.next(user)
	observer.complete()
}));

I mean talk about RxJS word salad. It’s a mess. And we don’t need to do this if we just use Tap!

Taking the above example and using Tap.

this.http.get<User>('api/user').pipe(tap(user => { 
	console.log(`Current User Is : ${user.name}`) 
}));

Notice how we used tap to write the console log, but we didn’t have to return the user object. It’s because we are saying that Tap will do something with the user object, but the original user should be returned to whoever is subscribing.

Another way to remember what tap does is that you are “tapping” into the result. Like a wiretap almost! You are listening in but (theoretically), you aren’t interfering with the existing conversation.

There is one caveat when using Tap though, and that is that the object inside the tap is still a reference to the original, it’s not a clone. So for example :

//This will return a user object with the firstName of test. 
this.http.get<User>('api/user').pipe(tap(user => { 
	user.firstName = 'Test';
}));

I personally prefer to use Tap only when the method inside the tap is safe and has no side effects that would alter the original result. If I am going to be altering the original result, I prefer to use the Map operator because that signals that we are “mapping” what the original result was to something new (Even if it’s only changing a single property).

A common issue when adding a required attribute to a textbox/textarea in an Angular application is that someone can just press space bar once, and the “required” validation is completed. A space counts as character!

The simple way to get around this is to use a regex pattern attribute to validate that there is more than just a space. Something like :

<input type="text" pattern="^(?!\s*$).+" />

But this quickly gets annoying to copy and paste everywhere. A better solution if you need to validate multiple fields the same way is to create a nice directive. Here’s one I prepared earlier :

import { Directive } from '@angular/core';
import { NG_VALIDATORS, Validator, ValidationErrors, AbstractControl } from '@angular/forms';

@Directive({
  selector: '[noWhitespace]', 
  providers: [{ provide: NG_VALIDATORS, useExisting: NoWhitespaceDirective, multi: true }]
})
export class NoWhitespaceDirective implements Validator {

  constructor() { }

  validate(control: AbstractControl): ValidationErrors {
    if(!control.value || control.value.trim() == '')
    {
      return {'required' : true };
    }

    return null;
  }

}

Simply place this on any text input/area control like so :

<input type="text" noWhitespace />

And you will now validate that the control has a value *and* that the value is not just whitespace. Easy!