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
read the file during server-side-rendering and
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.
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
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.