Angular is a powerful feature-rich platform that you can use to create all kinds of single-page apps, ranging from simple sites to more intricate ones. With it, you can build efficient native, web, and mobile apps with a wide range of tools and libraries it integrates. However, there are still ways apps built with it can be improved. For example, using Angular Universal, you can render your apps server-side to speed up page loads and improve SEO and performance.
Server-side rendering involves converting an app to HTML on a server. When you send a request for a particular path to the server, it returns an entirely static HTML page as a response. No additional requests need to be made to populate the page with data and resources as it is all contained in the response. The page appears almost precisely how it would be rendered client-side in the DOM but may sometimes have limited functionality.
Angular Universal is a set of tools that render Angular apps server-side. On the server, the Universal template engine takes an Angular app and creates static pages when a request is made. The pages are then forwarded to the client. It's likely called universal since it executes on other platforms besides a browser.
Server-side rendered apps load quicker to users. A static page is shown to the user to engage them as the rest of the application loads. The static pages that Angular Universal provides are simple to index when search engine web crawlers access them. This server-side rendering improves the SEO score of a site. In addition, SSR pages offer a better user experience, especially on less capable devices that may have trouble running full Angular apps.
Strapi is an open-source content API. Data from it can be consumed using REST or GraphQL. With it, you can set up APIs relatively fast. It also provides an admin panel where you can manage the API and content. You can use it with several different databases such as SQLite, MySQL, PostgresSQL, MongoDB, etc. Additionally, it is highly customizable and offers numerous plugins to supplement the API.
This article will cover how to use Strapi with an Angular Universal app. First, you'll set up a Strapi server. Then you will create an Angular Universal app that will consume data from Strapi.
Before you begin, you need to have Node installed. You can find out how to get it here. The version of Node needs to be at minimum 12 and at most 14. You also have to have the Angular CLI installed. This guide will walk you through how to do this.
To illustrate how to use Strapi with an Angular Universal app, you will build an app called Tour Events. It will list the event dates and venues of a touring performer. Strapi will provide the data for the events, and the Angular Universal app will consume and display it.
To begin, you will install Strapi and create a new project. The project will be called tour-server
.
1npx create-strapi-app tour-server --quickstart
Once the server starts, head on over to the admin panel at http://localhost:1337/admin. You will be prompted to create a new administrator. Once you create one, you will be routed to the dashboard.
Next, you will create a Tour Event
content type. This content type will serve as the structure for the event data you will add. Click the Content-Types Builder link in the side nav.
In the Content Types menu, click the Create new collection type link. You should see the pop-up below. Name the type Tour Event**s**, then click the Continue button.
In the next dialog, you will be prompted to add a field and pick a type. For example, the Tour Event**s type will have six fields: venue, date, city, region, country, and ticket link. So, you'll begin by creating a venue field that will be of type text**.
In the dialog, put in the venue like the name, then head on over to Advanced Settings.
In the Advanced Settings, make the field required by clicking the checkbox.
After which, click the Add another field button to create the rest of the five fields. The Tour Events type should look something like the image below when completed. Once done adding all the fields, click the Finish button.
The Tour Events type will now appear in the side nav. To add new events, click on the Tour Events link in the nav. It will show you all the available tour events. Then, click the Add New Tour Events button to display the view that adds new events.
Once you click the button, a pop-up form will be shown where you would add new events. Add a couple to act as dummy data.
The last thing you will need to do is enable the API to consume the event data. You will do this by clicking the Settings link in the side nav. Then, in the settings page under the Users & Permissions Plugin, click the Roles link. Next, you should see this page.
Under Permissions, there will be a list of checkboxes for Tour Event. Click the find checkbox, then save. This option will enable you to make GET requests for tour events.
If you go to http://localhost:1337/tour-events, it will display a list of tour events you created.
In this section, you will create the Angular app that will display the tour events. It will be called tour-app
. To create it, run:
1ng new tour-app
When prompted to add routing, select yes and pick CSS for styling. The app will only contain one component, but you will structure it to allow for more components in the future.
There will be two additional modules in the app: a features module and a core module. The core module will contain everything central to the app, like services and models. Finally, the features module will host the features of the app.
You can generate these modules by running:
1ng g m core
2ng g m features
Next, in the environments/environment.ts
file, you will add an apiUrl
to the environment
constant. This URL will point to the Strapi server.
1// src/environments/environment.ts
2export const environment = {
3 production: false,
4 apiUrl: 'http://localhost:1337/'
5};
After setting up the app, you will add a TourEvent
interface to the model's folder in the core module. You will generate it by running:
1ng g interface core/models/tour-event
Populate the file with the fields you created in the Strapi admin dashboard. This interface will be helpful when specifying return types for functions in different parts of the app.
1// src/app/core/models/tour-event.ts
2export interface TourEvent {
3 id: string;
4 city: string;
5 country: string;
6 date: Date;
7 region: string;
8 ticketsLink: string;
9 venue: string;
10}
To consume the Strapi API, you need to add the HttpClientModule
as an import to AppModule
.
1// src/app/app.module.ts
2import { HttpClientModule } from '@angular/common/http';
3...
4
5@NgModule({
6 ...
7 imports: [
8 ...
9 HttpClientModule
10 ]
11})
12export class AppModule { }
Next, you'll create a service for tour events. You will generate it as follows:
1ng g s core/services/tour-events
In the service file, you will create a getEvents
method that will hit the http://localhost:1337/tour-events route and return all the events. This service will look like this:
1// src/app/core/services/tour-events.service.ts
2import { HttpClient } from '@angular/common/http';
3import { Injectable } from '@angular/core';
4import { environment } from 'src/environments/environment';
5import { TourEvent } from '../models/tour-event';
6
7@Injectable({
8 providedIn: 'root'
9})
10export class TourEventsService {
11 private eventsPath = 'tour-events';
12
13 constructor(private http: HttpClient) { }
14
15 getEvents(){
16 return this.http.get<TourEvent[]>(environment.apiUrl+this.eventsPath);
17 }
18}
Lastly, you will create the TourEventsComponent
. This component will serve as the page that will display all the tour events from the service. You will generate it by running:
1ng g c features/tour-events
You will then inject the TourEventsService
in the constructor and call its getEvents
method and assign the results to the events$
property, which you will use in the template.
1// src/app/features/tour-events/tour-events.component.ts
2import { Component } from '@angular/core';
3import { TourEventsService } from 'src/app/core/services/tour-events.service';
4@Component({
5 selector: 'app-tour-events',
6 templateUrl: './tour-events.component.html',
7 styleUrls: ['./tour-events.component.css']
8})
9export class TourEventsComponent {
10 events$ = this.eventService.getEvents();
11 constructor(private eventService: TourEventsService) { }
12}
In the template, create a table with five columns corresponding to the fields of an event. For the table data, you shall loop through the events.
1<!-- src/app/features/tour-events/tour-events.component.html -->
2<h1>Tour Events</h1>
3<table *ngIf="events$ | async as events">
4 <tr>
5 <th>Date</th>
6 <th>Venue</th>
7 <th>City</th>
8 <th>Time</th>
9 <th>Tickets</th>
10 </tr>
11 <tr *ngFor="let event of events">
12 <td>{{event.date | date: 'fullDate'}}</td>
13 <td>{{event.venue | titlecase}}</td>
14 <td>
15 <span *ngIf="event.region">{{event.city | titlecase}}, {{event.region | uppercase}} ({{event.country |
16 uppercase}})</span>
17 <span *ngIf="!event.region">{{event.city | titlecase}} ({{event.country | uppercase}})</span>
18 </td>
19 <td>{{event.date | date: 'shortTime'}}</td>
20 <td><a href="{{event.ticketsLink}}">Tickets</a></td>
21 </tr>
22</table>
This is how you would style the component.
1/* src/app/features/tour-events/tour-events.component.css */
2* {
3 font-family: arial, sans-serif;
4}
5
6h1 {
7 text-align: center;
8}
9
10table {
11 border-collapse: collapse;
12 width: 100%;
13}
14
15td, th {
16 border-bottom: 1px solid lightgray;
17 text-align: left;
18 padding: 8px;
19}
20
21tr:nth-child(even) {
22 background-color: #f5f5f5;
23}
In the app routing module, add a route for the TourEventsComponent
so you can preview it.
1// src/app/app-routing.module.ts
2...
3import { TourEventsComponent } from './tour-events/tour-events.component';
4import { Routes, RouterModule } from '@angular/router';
5
6const routes: Routes = [
7 { path: '', component: TourEventsComponent}
8];
9
10@NgModule({
11 declarations: [
12 TourEventsComponent
13 ],
14 imports: [
15 ...
16 RouterModule.forChild(routes)
17 ]
18})
19export class FeaturesModule { }
Before you can run the app, be sure to replace the contents of app.component.html
with just:
1<!-- src/app/app.component.html -->
2<router-outlet></router-outlet>
Now to run the app:
1ng serve
Head on over to http://localhost:4200 and you should see something similar to this:
The Angular CLI comes in handy when setting up server-side rendering. Angular Universal uses a Node.js Express server to create static HTML pages and respond to requests. Then, the pages are rendered using the Universal template engine.
It takes the path of a request, a module containing components, and a template page. It uses the path to decide what components to use, renders the view within the template, and generates an HTML page. The page is then served to the client.
To make the server-side app module, run:
1ng add @nguniversal/express-engine
Running the above command will add required dependencies, a web server, a server module, and other settings needed for server-side rendering. To preview the SSR site, run:
1npm run dev:ssr
The app will be available at http://localhost:4200 as before. The site should look the same as the screenshot above. The only difference is the view will be a complete HTML page.
Angular Universal sites are great for SEO, have fast load times and better performance. However, just because they are rendered server-side, it doesn't mean that consuming external APIs becomes more complex. Using Strapi, you can build APIs that Angular Universal apps can consume without much issue.
To read more about Angular Universal, head to this link. For more on what you can do with Strapi, check out their resource center. You can find the code for this project here.
This article is a guest post by Zara Cooper. She wrote this blog post through the Write for the Community program.
Zara is a software developer and technical writer, using React Native, React, Rails, Node, Golang, Angular and many more technologies.