Contact Us

Server Side Rendering with Angular 14

 - 
June 4, 2022
Server side rendering with Angular 14

Single page web applications are very interesting and very useful, and that is why they are replacing the old desktop software. Web apps have a lot of advantages over desktop apps. They are so much easier to build and to maintain, flexible and easy to use and they can be used in different devices and systems (Web, Mobile, Desktop…). 

JavaScript is the most popular scripting language for web development. It has many frameworks that make web application development much easier like Angular, React and Vue JS for the client side and Node JS, Express JS for the backend side.

 Frontend frameworks are very useful, and they help to build high quality scalable web applications. However, they have a very big issue when it comes to SEO, because search engines crawlers find it very difficult to crawl single page web applications. They don't render HTML at the first time when the app runs. Server side rendering will solve this issue by generating HTML files in the server side and rendering them to web crawlers before the app renders.

What is Angular ?

If you are an Angular developer or you are familiar with it, then feel free to skip this section. 

Angular is an open-source single page web application JavaScript framework that was developed by google in 2009. Angular is one of the most popular frontend frameworks. It provides a lot of advanced features in web development such as two way binding, component concept…

A lot of big tech companies uses Angular to build their applications like PayPal, Microsoft, Upwork, Gmail… which means this framework is really powerful.

What is Angular Universal ?

What is Angular Universal ?

We all know that single page applications normally executes in the browser, but that is not very helpful to search engine crawlers because it is difficult for them to detect all pages in the app. Angular universal executes in the server side and generates all the pages in our application as static pages, and then all the pages will be sent to the client side.

Angular universal is an open-source solution for server side rendering with angular. It is really helpful because it improves the performance of the application, search engine optimization and will make the application much faster.

You maybe wondering why you should use Angular universal or what are the benefits of this solution, so let’s talk a little bit about the benefits about angular universal.

Search engine optimization improvement

The rule number one in the internet is if you want your website to be in the top result of google search you need to optimize your website for SEO by putting a good title, a good description, put images with alt attributes and much more. Now, the problem is that single page applications are executed and rendered as JavaScript code and not HTML or CSS and search engine crawlers ignore JavaScript because they need HTML and CSS…

Basically, Angular universal will generate HTML files on the server and then send them back to the client before the real application get rendered. And like that web crawlers will be able to detect each and every web page in our website.

User experience improvement

Since angular universal generates HTML files in the server side and render them to the client side before the actual app get rendered, then the user will not wait until the app get rendered to see something in the webpage. The visitor will actually see the content in the website before the actual web application get rendered which is really amazing.

Server side rendering with Angular 13 Implementation

Now that you understand the basics of how server side rendering works with Angular and using Angular universal, let’s jump to the code and see how we can implement this amazing feature in a real angular application. For the purpose of this blog, we will build a simple CRUD application where we will show you exactly step by step how to implement server side rendering. We will use the MEAN Stack to develop this CRUD application. (Angular, Node JS, Express JS, Mongo DB).

First of all, you need to setup a blank Angular project, and to do that run the following command. 

ng new ssr-crud-application

Once the installation  of the project is done, open the folder of your project in VS code or any code editor you prefer and run the following command to run the Angular server.

ng serve

Now that you are sure your application is working and there was no error during the installation. Let’s add angular universal to our app.

Run the following command which will add all the necessary packages to implement Angular universal.

ng add @nguniversal/express-engine

This command will add Angular universal and its dependencies, and also a node js server which will generate the HTML files and serve them to the browser while running the app. It will add some required packages to get angular universal up and running, and it will also create a file server.ts which holds the node js code. And if you take a look into your package.json file you will find some new commands such as build:ssr and serve:ssr…

This command may actually take some time, so just wait for it to finish, and then run the following command in order to run the server and launch the app.

npm run build:ssr
npm run serve:ssr

After running this two commands, the server of your application will be up and running. Go to your browser and head it to  http://localhost:4200/ . Make sure that this is the right port your app is running on.

As you can see, your application is up and running and if you click to see the source code, you will notice that there is content in the source code and it’s not empty, and that is the power of SSR.

Please note that if you are using some variables like document, localStorage… you need to check if this code is running on server or client, because the server will never understand these variables. You can do that using Platform service in Angular.

Now, let’s work on the backend side of our project, we need to setup a new Node JS project. We can do that by opening the terminal and running the following command. 

npm init

Now go ahead and open your project in VS Code, and create the server.js file. Before diving into the code and how to create node js server let’s install some important packages.

npm install express body-parser mongodb mongoose

This command will simply install these 4 packages (express, mongodb, mongoose and body parser). 

Put the following code in your server.js file in order to create a node js server.

const http = require('http');
const app = require('./app');
const dbConnection = require("./config/db");


  const onListening = () => {
    const addr = server.address();
    const bind = typeof port === 'string' ? 'pipe ' + port : 'port ' + port;
    console.log('Listening on ' + bind);
  };
  
  const port = 3000;
  app.set('port', port);
  
  const server = http.createServer(app);
  
  server.on('listening', onListening);

// Setup Connection to Database
const dbConnection = (server, port) => {
        mongoose
            .connect(
                process.env.MONGO_URI, {
                    useNewUrlParser: true,
                    useUnifiedTopology: true,
                  }, (err) => {
                    if (err) {
                        console.log(err);
                        throw new Error('Error on connecting to database');
                    } else {
                        console.log('Connected to database');
                        server.listen(port);
                    }
                }
            )
}
dbConnection(server, port)

Let’s define the schema of our model which will be a book. Create a folder in your node js project and name it models. Under this folder create a .js file and name it Book.js and put the following code in the file.

import mongoose, { Schema } from 'mongoose';
let BookSchema: Schema = new Schema({
    name: {
        type: String,
        required: true
    },
    author: {
        type: String,
        required: true
    }
}, {
    collection: 'books'
})
export default mongoose.model('Book', BookSchema);

Now that we created our model, let’s create the rest API using Express JS. The same way we did with the model, you need to create a folder and name it routes and under this folder create a .js file and name it book-routes.js, and then put the following code.

const express = require("express");
const router = express.Router();


router.post("/", (req, res) => {
   const book= new Book(req.body);

    book.save().then((book) => {
        res.json(book);
    }).catch(err => {
        res.json(err);
    })
});

router.put("/:id", (req, res) => {
     Book.updateOne({ _id: ObjectId(req.params.id) }, req.body).then((result) => {
        res.json(result);
    }, (err) => {
        res.json(err);
    });
});

router.delete("/:id", (req, res) => {
    Book.deleteOne({ _id: ObjectId(req.params.id) }).then((result) => {
        res.json(result);
    }).catch(err => {
        res.json(err);
    })
});

router.get("/all", (req, res) => {
    Book.find({}).then(books=> {
        if (books.length > 0) {
            res.json(books.reverse())
        } else {
            res.status(404).json("No books Found");
        }
    }).catch(err => {
        res.json(err);
    })
});

router.get("/:id", (req, res) => {
    Book.findOne({ _id: ObjectId(req.params.id) }).then((book) => {
        res.json(book);
    }).catch(err => {
        res.jsn(err);
    })
});

module.exports = router;

As you can see, we have created our book api and we implemented all the four main methods of Rest API Get, Post, Put, Delete.

Go ahead and test your API using Postman or Insomnia or any other api tester you prefer.

Make sure you launched the node JS server by running the following command.

node server.js

Building the frontend side of the project

Server side rendering with Angular Universal in Angular 14

Our application is a simple CRUD application, so we need to have three main pages in our Angular application which will be add-book, edit-book and list-books components. Run the following command to create these three components.

  • ng g c components/add-book
  • ng g c components/edit-book
  • ng g c components/list-books

Your app.module.ts file should look like this.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AddBookComponent } from '../app/components/add-book/add-book.component';
import { EditBookComponent } from '../app/components/edit-book/edit-book.component';
import { ListBooksComponent } from '../app/components/list-books/list-books.component';

@NgModule({
  declarations: [
    AppComponent,
    AddBookComponent,
    EditBookComponent,
    ListBooksComponent,
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'serverApp' }),
    AppRoutingModule,
  ],
  providers: [],
  bootstrap: [AppComponent],
})

export class AppModule {}

Your app-routing.module.ts file should be like this

import { NgModule } from '@angular/core';
import { AddBookComponent } from '../app/components/add-book/add-book.component';
import { EditBookComponent } from '../app/components/edit-book/edit-book.component';
import { ListBooksComponent } from '../app/components/list-books/list-books.component';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
  {
    path: '',
    redirectTo: '/add-book',
    pathMatch: 'full'
  },
  {
    path: 'add-book',
    component: AddBookComponent
  },
  {
    path: 'edit-book/:id',
    component: EditBookComponent
  },
  {
    path: 'books',
    component: ListBooksComponent
  }
];
@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Book model

export interface Book {
   _id?: string;
   name?: string;
   author?: string;
   createdAt?: Date;
   updatedAt?: Date;
}

We also need to create a service to communicate with our API by running the following command

ng g s book

Your service file should look like this

import { Injectable } from '@angular/core';
import { Book} from './book';
import { Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';
@Injectable({
  providedIn: 'root'
})
export class BookService {
  constructor(
    private http: HttpClient
  ) { }
  addBook(book: Book): Observable<any> {
    return this.http.post<Book>('/api/create-book', book);
  }

  getBooks(): Observable<Book[]> {
    return this.http.get<Book[]>('/api/get-books');
  }

  getBook(id): Observable<Book[]> {
    return this.http.get<Book[]>('/api/get-book/' + id);
  }

  updateBook(id, book: Book): Observable<any> {
    return this.http.put('/api/update-book/' + id, book);
  }

  deleteBook(id): Observable<Book[]> {
    return this.http.delete<Book[]>('/api/delete-book/' + id);
  }
}

The book template will look like this.

<table class="table">
    <thead class="table-primary">
        <tr>
            <th scope="col">#</th>
            <th scope="col">Book name</th>
            <th scope="col">Author name</th>
            <th scope="col">Action</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let book of books">
            <th scope="row">{{book._id}}</th>
            <td>{{book.name}}</td>
            <td>{{book.author}}</td>
            <td>
                <span class="edit" [routerLink]="['/edit-book/', book._id]">Edit</span>
                <span class="delete" (click)="removeBook(book, book._id)">Delete</span>
            </td>
        </tr>
    </tbody>
</table>

Display and delete books will look like this.

import { Component, OnInit } from '@angular/core';
import { BookService } from '../../shared/book.service';
@Component({
  selector: 'app-list-books',
  templateUrl: './list-books.component.html',
  styleUrls: ['./list-books.component.scss']
})
export class ListBooksComponent implements OnInit {
  books: any = [];
  constructor(private bookService: BookService) {
    this.bookService.getBooks().subscribe((item) => {
      this.books = item;
    });
  }
  ngOnInit() { }
  removeBook(employee, i) {
    if (window.confirm('Are you sure?')) {
      this.bookService.deleteBook(employee._id)
        .subscribe((res) => {
          this.books.splice(i, 1);
        }
      )
    }
  }
}

Conclusion

In this article we learnt how to build a MEAN Stack CRUD application while implementing the server side rendering concept using Angular universal. We also created an API for our book model. I hope all of this will help you build your dream application without thinking about the SEO because you will use the server side rendering mechanism which is amazing with SEO.

Thank you so much for reading this article.

Web Design Services

Looking for a web design agency to bring your business online and build the website you need to get more high quality clients ?
GrowYourBusiness.tech agency is ready to help you build your beautiful looking website.

Latest Blogs

We are a team of creative thinkers and problem solvers dedicated to expanding the limits of what is possible by helping brands achieve their goals.

Social Media

Copyright © 2021 Grow Your Business. All rights reserved.
crossmenu