September 24, 2020

Angular Transfer state API use and example

Transfer state is a universal common module which shares data between client side and server side.

First of all, Let me tell you brief about angular universal. Angular universal is a technology that renders angular application on server side which is useful for SEO, fast page loading, Better social media preview, which is not possible using client side angular application because angular application is a single page application where most of the functionality dependent upon javascript which executed dynamically but, it has some disadvantage like its not crawlable because of its dynamic in nature where every crawlers dont understand javascript so that’s why angular universal comes into the picture. For more details please refer this link

This is a brief about angular universal, let’s discuss the how trasfer state module help us to manage angular application.

After server-side rendering, angular rerun all the functionality on the browser to create client-side view it means all XHR will make again and this will create extra load on your back-end server and crawlers also get confused that page is still loading or what?

So to avoid this kind of issue transfer state comes for rescue. Transfer state module stores data on the server in a key-value format and we can access that one on client side with the same key which is used on server.

Please subscribe for web development tutorials

To setup transfer state you need to import two modules one on client app module ie BrowserTransferStateModule and other one on server app module ie ServerTransferStateModule. For eg.

import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'serverApp' }),
    AppRoutingModule,
    BrowserTransferStateModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Above one is for client side app.module.ts

import { NgModule } from '@angular/core';
import { ServerModule, ServerTransferStateModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { ModuleMapLoaderModule } from '@nguniversal/module-map-ngfactory-loader';
@NgModule({
  imports: [
    AppModule,
    ServerModule,
    ModuleMapLoaderModule,
    ServerTransferStateModule
  ],
  bootstrap: [AppComponent],
})
export class AppServerModule {}

And this one is for server app.server.module.ts.

Now, Lets use transfer state module methods

import { Injectable } from '@angular/core';
import { TransferState } from '@angular/platform-browser';
import { Observable, from } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { tap } from 'rxjs/operators'
@Injectable({
  providedIn: 'root'
})
export class TransferHttpService {
  constructor(private transferHttp: TransferState, private httpClient: HttpClient) { }
  get(url, options?): Observable<any> {
    return this.getData(url, options, () => {
      return this.httpClient.get(url, options)
    })
  }
  post(url, body, options?): Observable<any> {
    return this.getData(url, options, () => {
      return this.httpClient.post(url, body, options)
    })
  }
  delete(url, options?): Observable<any> {
    return this.getData(url, options, () => {
      return this.httpClient.delete(url, options)
    })
  }
  put(url, body, options?): Observable<any> {
    return this.getData(url, options, () => {
      return this.httpClient.put(url, body, options)
    })
  }
  getData(url, options, callback: () => Observable<any>): Observable<any> {
    const optionsString = options ? JSON.stringify(options) : '';
    let key = `${url + optionsString}`;
    let result;
    try {
      return this.resolveData(key)
    } catch (e) {
      console.log('In catch')
      return callback()
        .pipe(tap((data) => {
          console.log('cache set')
          this.setCache(key, data);
        }))
    }
  }
  resolveData(key) {
    let resultData: any;
    if (this.hasKey(key)) {
      resultData = this.getFromCache(key);
    } else {
      throw new Error()
    }
    return from(Promise.resolve(resultData))
  }
  setCache(key, value) {
    this.transferHttp.set(key, value)
  }
  getFromCache(key) {
    return this.transferHttp.get(key, null) // null set as default value
  }
  hasKey(key) {
    return this.transferHttp.hasKey(key)
  }
}

In above example, we have created a service where we created three methods get, post and delete, In all these methods we are using getData() method where it checks that data is present in the cache or not if not then it’s making HTTP API call. For better understanding divide it into three parts

  • An application running on the server-side, Means the first time it’s executing then it will make HTTP API call because it transfer state couldn’t find data in the cache.
  • Response from API storing into the transfer state cache against the particular key.
  • After that when application rendering on client-side hasKey method will check for that data is present in the cache or not if it present data will retrieve from the cache instead of making extra API call.

This is all about transfer state module which mainly used for sharing data from server side angular app to client side angular app.If you love this post please share it.

Leave a Reply

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