Angular, SEO

Display dynamic content in angular universal

Spread the love

This guide help Angular Universal, a technology that renders dynamic content on the server in your Angular applications.

A normal Angular universal application view source does not display dynamic content in angular universal, rendering pages in the DOM before api call happened in component. Angular Universal executes on the server, generating static application pages that later get bootstrapped on the client. For rendering dynamic content in angular universal you have to resolve dynamic data before navigate to the route path.

Angular Universal and Server Side Rendering of dynamic content step by step

This example will show you one route path that resolve your dynamic content from your backend.

Step:1=> AppRoutingModule Setup

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { LayoutComponent } from './layouts';
import { RouteResolver} from './resolvers';

const appRoutes: Routes = [
	{
		path: '',
		component: LayoutComponent,
		children: [
			{
				path: '',
				resolve: { result: RouteResolver },
				data: {},
				loadChildren: () =>
					import(
						'./pages/home-page/homePage.module'
					).then((m) => m.HomePageModule)
			}
                 ]
            }
]
@NgModule({
	imports: [
		RouterModule.forRoot(appRoutes, {
			initialNavigation: 'enabled',
			onSameUrlNavigation: 'reload'
		})
	],
	exports: [RouterModule]
})
export class AppRoutingModule {}

Step:2 => Route Resolver service setup

import { map, Observable } from 'rxjs';
import { HttpService } from './http';
import { Injectable } from '@angular/core';
import {
	Resolve,
	RouterStateSnapshot,
	ActivatedRouteSnapshot
} from '@angular/router';

@Injectable()
export class RouteResolver implements Resolve<any> {
	constructor(private _http: HttpService) {}


	resolve(
		route: ActivatedRouteSnapshot,
		state: RouterStateSnapshot
	): Observable<any> | undefined {
		const param = route.data;
		return this._http.get('homePageContent']).pipe(
			map((result) => {
				return result.response.dataset;
			})
		);
	}
}

Step: 3 => Dynamic data display in component

@Component({
	selector: 'home-page',
	templateUrl: './home-page.component.html',
	styleUrls: ['./home-page.component.scss']
})
export class HomePageComponent implements OnInit {

        public homePageContent:any;

        constructor(private _route: ActivatedRoute
) {
}

        ngOnInit(): void {
		this.homePageContent = this._route.snapshot.data['result'];
	}
}

Step: 4 => Common Http Service setup

import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { environment } from '@env/environment';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import FormData from 'form-data';

export type IRequestType = 'DELETE' | 'GET' | 'HEAD' | 'POST' | 'PATCH' | 'PUT';

export interface IRequestOptions {
	useUrlPrefix?: boolean;
	headers?: any;
	observe?: 'body' | 'events' | 'response';
	reportProgress?: boolean;
}
export function isObject(arg: any) {
	return typeof arg === 'object' && arg !== null && !(arg instanceof Array)
		? arg
		: false;
}

@Injectable({
    providedIn: 'root',
})
export class HttpService {
	constructor(private _http: HttpClient) {}

	private request(
		method: IRequestType,
		url: string,
		params?: Object | null,
		options?: IRequestOptions
	): Observable<any> {
		let data;
		let reqUrl = url;
		let request$: Observable<any>;
		let reqOptions: any = { useUrlPrefix: true };

		if (isObject(options)) reqOptions = Object.assign(reqOptions, options);

		// Creating request headers
		if (reqOptions.headers) {
			reqOptions.headers = new HttpHeaders(reqOptions.headers);
		}

		// Assigninig params
		if (params !== null && isObject(params)) {
			if (params instanceof FormData) {
				data = params;
				reqOptions.reportProgress = reqOptions.reportProgress || true;
			}
			data = params;
		}

		// Checking url prefix
		if (reqOptions.useUrlPrefix === true) {
			const urlHost =
				urlType === 'D' ? environment.host : environment.hostBooking;
			reqUrl = urlHost + '/' + url;
		}

		reqOptions.body = data;
		reqOptions.observe = reqOptions.observe || 'body';

		// Final Request
		request$ = this._http.request(method, reqUrl, reqOptions);

		request$.pipe(
			map((response: HttpResponse<any>) => {
				const responseObject = response.body;
				return responseObject;
			})
		);
		return request$;
	}

	public post(
		url: string,
		params?: any,
		options?: IRequestOptions
	) {
		return this.request('POST', url, params, options);
	}

	public get(url: string, options?: IRequestOptions) {
		return this.request('GET', url, null, options);
	}
}

Step: 5 => AppModule setup

import { NgModule } from '@angular/core';
import {
	BrowserModule,
	BrowserTransferStateModule
} from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';


import { TransferHttpCacheModule } from '@nguniversal/common';

@NgModule({
	declarations: [AppComponent],
	imports: [

		AppRoutingModule,

		TransferHttpCacheModule,
		BrowserAnimationsModule,
		BrowserTransferStateModule,
		BrowserModule.withServerTransition({ appId: 'serverApp' })
	],
	providers: [],
	bootstrap: [AppComponent]
})
export class AppModule {}

References

Thank you! Like our Facebook page to get more updates.


Spread the love
Tagged , , , ,

About Chandra

Technology lover. Professionally Software Developer and write some Technical Blog to help newcomer.
View all posts by Chandra →

Leave a Reply

Your email address will not be published.