Angular 5 - How to use LocalStorage, Window, Document and other browser types in Angular Universal

Angular 5 - How to use LocalStorage, Window, Document and other browser types in Angular Universal

Developing an Angular Universal (aka isomorphic) application means to write code that can be rendered everywhere, regardless of the client: a web browser, a mobile app, a server-side Node.JS or ASP.NET service that does the prerendering, and so on. This has big advantages in terms of performances, scalability and SEO, but it also comes with some downsides that we need to understand.

The most important of them - and the one causing more issues - is probably the fact that some "global" Javascript objects known as browser types, such as  window , document , navigator  and so on are not so "global" anymore: when writing JS code using an universal/isomorphic approach we can't take them for granted because they simply do not exist on the server, which is one of the contexts we need to take care of.

To better explain this, it means that we can't do this:

Because it will definitely generate an error during the server-side prerendering phase.

If we need to use these objects, we need to wrap them into a conditional code block that will ensure they'll be executed only in the appropriate context: in other words, we need to execute these kind of instructions situationally within our JS code, thus adopting an isomorphic approach.

Luckily enough, Angular provides us a way to easily do so by making available two very useful objects:

  • The PLATFORM_ID  token (part of the @angular/core  package), which can identify the executing platform's type.
  • The isPlatformBrowser  and isPlatformServer  methods (from @angular/common), which can be used - in conjunction with the aforementioned PLATFORM_ID  - to check whether the current platform is browser or server.

Thanks to these two objects we can easily pull off something like this:

These conditional blocks can be put anywhere within our Angular component's code.

IMPORTANT: Writing isomorphic code and writing decent Angular code are two different things: no matter how conditional and situational our code might be, if we use a global object within an Angular component it means that we're dealing with this stuff in a bad way. To better understand this concept, I strongly suggest to read this post.

If you want to know more about .NET Core and Angular check out the ASP.NET Core 2 and Angular 5 book, available in paperback and/or digital format. Promo Code: ASPCA50 to get it with a 50% discount! The book's latest edition, updated to ASP.NET Core 5 and Angular 11, is available here.

For more info about Angular Universal and isomorphic JavaScript check out the following resources:

 

About Ryan

IT Project Manager, Web Interface Architect and Lead Developer for many high-traffic web sites & services hosted in Italy and Europe. Since 2010 it's also a lead designer for many App and games for Android, iOS and Windows Phone mobile devices for a number of italian companies. Microsoft MVP for Development Technologies since 2018.

View all posts by Ryan

2 Comments on “Angular 5 - How to use LocalStorage, Window, Document and other browser types in Angular Universal”

  1. Pingback: Angular 5 - Access Window, Document, LocalStorage in Angular Universal
  2. Hi. I’m trying to figure out the Universal aspect of Angular for a component I’m working on.

    I’m finding that there are some things that the Angular system just can’t deal with – without reverting to native Web API’s. For example the content we recieve is markdown, which is then injected into the innerHtml of an Angular component after being processed by marked.js. Angular has no way of accessing the generated HTML, apart from using ElementRef.nativeElement of the parent component, and then doing a querySelectorAll for the elements we need to retrieve. But, using nativeElement is not recomened by Angular. Can we use Renderer2 to solve this – not from my experience, as it also needs ElementRef.nativeElement, which will be null on the server.
    What are your thoughts on this?

Leave a Reply

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.

This site uses Akismet to reduce spam. Learn how your comment data is processed.