Using Node.js in Angular and TransferState

In this post, we're going to learn how to use Node.js in your Angular app and pass data between the backend and the frontend. Angular Universal provides a tool called TransferState that will help you prevent duplicate data fetching -- it's super handy and a bit advanced.

Below is a tutorial that introduces the ideas of TransferState and how to use it, but if you want a step-by-step walkthrough with complete code, then grab a copy of the course. The course is about 270+ pages over 40 lessons that teach every step to creating blazing fast Angular apps.

The Problem and TransferState#

Angular Universal is a powerful tool to address the SEO pitfall of Single Page Applications. Unfortunately, it's not a magic wand, and sometimes you need to adjust your application to make it efficient. Such a problem occurs when your application performs an HTTP call (to the back-end) during the initialization. Does it make sense to perform that call as well in the back-end as in the front-end?

Let's assume we're building a task application and we have a text-file tasks.json on our server, with the following in it:

We could implement a back-end endpoint that will read the file content and send it back to the requester, e.g. from our express server:

And then load this file via an HTTP request.

But with Universal, we can take this one step further and

  1. read the file during server-side-rendering and

  2. pass the information to the client on render

Of course, we don't want Angular to perform HTTP calls when running on the server when we don't have to. And so with Universal we can use Node.js APIs like fs and just read the file directly.

Here's how we could create the TasksService equivalent on the server:

It's okay if you do a double-take on the above: isn't this Angular code? Yes it is, but that's the sort of thing we're able to do with Universal.

Let's say we want to use this TaskService in a component. Here's what it could look like:

Now if we were to load this page and view the Network tab, we'd see that we're still making a call to /tasks.json - but we don't need to!

It would be great to introduce a mechanism that passes such data along with the application bundle. That's what TransferState is for.

Introducing TransferState#

To use TransferState we first create StateKeys to identify the data we want to transfer to the browser:

Then we update the getTasks() method to set entry to the TransferState registry when data is read from the filesystem:

From now, the TransferState registry will contain the TASKS entry. The registry will be passed along with the rendered view to the browser!

The browser side#

Now on the browser side, we need to configure it to read from the StateKeys if they exist.

To do this, we inject the TransferState service, and then update getTasks() to retrieve data from the TransferState registry or fall back to an HTTP request when the registry is empty:

Testing the TransferState#

Now if we navigate to our app, we can verify in the Network tab of the Developer Tools:

And if we hit the refresh list button and we would see that the new list is retrieved via HTTP, rather than from the TransferState.


Above is a quick introduction to the ideas, but of course, there are specific things you need to do to implement it for real. We walk through those details in the course. You can grab your copy here OR as part of a newline pro membership.