1. Creating the Base Application
Learning Objectives
By the end of the chapter, you will be able to:
- Build a modular Angular app using Angular CLI
- Implement a reusable user interface module based on the Bootstrap framework
- Implement application logic using a clean separation of concerns
- Use services to retrieve data from a REST API
- Use resolvers to make sure that the data is loaded before navigating to the page
This chapter introduces us to Angular CLI and how to use it to create a new application. Here, we will create the various components and implement the logic for our app.
Introduction
Server-Side Rendering
When we talk about the server-side rendering of websites, we generally refer to an application or website that uses a programming language that runs on a server. On this server, web pages are created (rendered) and the output of that rendering (the HTML) is sent to the browser, where it can be displayed directly. Examples of this include PHP, Java, Python, .NET, and Ruby.
Strengths
The benefits of server-side rendering is that the generation happens on a server, making it ready to consume in the browser once it's downloaded. It works great with indexing by search engines and with sharing on social media. The content is ready to be consumed, and the client (in this case, the search engine) does not need to run any code to analyze the page.
Weaknesses
The downside of server-side rendering is that the pages often have only basic possibilities of interaction with the user, and when the content changes, or the user navigates to another page, they have to re-download the whole page. This results in more bandwidth and gives the user the feeling that the page is loading slower than it actually is.
Client-Side Rendering
When we talk about client-side rendering, we generally refer to an application or website that uses JavaScript running in the browser to display (render) the pages. There is often a single page that is downloaded, with a JavaScript file that builds up the actual page (hence the term single-page application).
Strengths
The benefit of client-side rendering is that the pages are highly interactive. Parts of the page can be reloaded or updated without having to refresh the whole browser. This uses less bandwidth and it generally gives the user the feeling that the website or application is very fast. The server can be mostly stateless as the page is not rendered there; it just serves the HTML, JavaScript, and stylesheets one time and is done. This takes load off the server, and this results in better scalability.
Weaknesses
Client-side rendered websites are difficult for a search engine to index, as they need to execute the JavaScript to display how the page looks. This is also the case when sharing links to the sites on social media, since these are generally static instead of dynamic.
Another weakness is that the initial download is bigger, and this can be an issue on, for instance, mobile devices with slow connections. Users will see a blank page until the whole application is downloaded, and maybe they will just use a small part of it.
In this chapter, we will create an Angular application that is used throughout this book.
The Angular application we will build is going to be a list of posts that you regularly see on a social networking site such as Twitter. From the list of posts, we can click a link that brings us to the post detail page. We will intentionally keep the application simple as this book is meant to focus on the technology rather than the functionality of the app. Although the app is simple, we will develop it using best practices for Angular development. It should be easy for any Angular developer to extend on the logic and structure that is shown in this application.
Installing Angular CLI
Angular CLI is the officially supported tool for creating and developing Angular applications. It's an open source project that is maintained by the Angular team and is the recommended way to develop Angular applications.
Angular CLI offers the following functionalities:
- Create a new application
- Run the application in development mode
- Generate code using the best practices from the Angular team
- Run unit tests and end-to-end tests.
- Create a production-ready build
- Easily install and add third-party software (using
ng add
, since version 6)
One of the main benefits of using Angular CLI is that you don't need to configure any build tools. It's all abstracted away and available through one handy command: ng
.
Throughout this book, we will be using the ng
command for creating the app, generating the code, running the application in development mode, and creating builds.
Note
For more information about Angular CLI, refer to the project page on GitHub at https://github.com/angular/angular-cli.
Exercise 1: Installing Angular CLI
In this exercise, we will use npm
to globally install Angular CLI. This will give us access to the ng
command, which we will use throughout this book:
- Open your terminal.
- Run the following command:
npm install -g @angular/cli@latest
- Once this command has finished running without any errors, we can make sure that the
ng
command works as expected by running the following command:ng --version
Verify that the output is similar to the output shown here:

Figure 1.1: Installing Angular CLI
We now have Angular CLI installed and we are ready to get started!
Creating a New Application
Now that we have installed and configured Angular CLI, we will start by generating a new application.
Running the ng new
command will do the following:
- Create a folder called
angular-social
. - Create a new application inside this folder.
- Add a routing module (because of the
--routing
flag). - Run
npm install
inside this folder to install the dependencies. - Run
git init
to initialize a new Git repository.
The following is the folder structure of an Angular CLI app:
src
: This folder contains the source files for the application.src/app/
: This folder contains the application files.src/assets/
: This folder contains the static assets we can use in the application (such as images).src/environments/
: This folder contains the definition of the default environments of the application.e2e
: This folder contains the end-to-end tests for the application.
Exercise 2: Creating a New Application
In this exercise, we will create a new application. Follow these steps to complete this exercise:
- Open the terminal and navigate to the workspace directory where you want to work on the application:
cd dev
- Inside the workspace directory, invoke the
ng
command, as follows:ng new angular-social
- Answer
Y
to the question about generating a routing module. - For the stylesheet format, we will select CSS.
The application will be generated using these options in the
angular-social
directory, as shown in the following screenshot:

Figure 1.2: Creating a new application
Exercise 3: Starting the Development Server
In this exercise, we will start the development server. Follow these steps to complete this exercise:
- Open the terminal and enter the working directory:
cd angular-social
- Use
ng serve
to start the development server:cd angular-social ng serve

Figure 1.3: Serving the application
Exercise 4: Browsing to the Application
In this exercise, we will navigate to the default page of our application. Follow these steps to complete this exercise:
- Open your browser and navigate to
http://localhost:4200/
. - You should be greeted with a default page that says Welcome to angular-social!:

Figure 1.4: Browsing to the application
Configuring Global Styles
The default generated Angular application does not have any styling. Angular does not dictate anything in terms of style. This means that in your own projects you can use any CSS framework like Bootstrap, Angular Material, Foundation, Semantic UI, or one of the many others.
Alternatively, it's possible to create a custom style from scratch to get a unique look and feel. For this book, though, we will stick to Bootstrap 4 and Font Awesome, as they are widely used and provide a decent style with a minimal amount of code.
Font Awesome is a so-called icon font. You can include it in your page and then use it to show icons by applying some classes to an empty <i class=""></i>
tag.
Linking to the Stylesheets in the Global styles.css File
As mentioned in the previous section, the application has a global stylesheet named src/styles.css
.
In this stylesheet, we will use the @import
command to link to Bootstrap and Font Awesome. This will instruct Angular to download those files and apply the style to the application globally.
Note
For a list of all available icons, you can refer to the Font Awesome icon list at https://fontawesome.com/v4.7.0/icons/. For an overview of all available Bootstrap styles, you can refer to the Bootstrap 4 documentation at https://getbootstrap.com/docs/4.1/getting-started/introduction/. To easily apply a different theme to the app, you can switch out Bootstrap with one of the BootSwatch themes at https://www.bootstrapcdn.com/bootswatch/.
Exercise 5: Installing Bootstrap and Font Awesome
In this exercise, we will add Bootstrap and Font Awesome to the global stylesheet. Follow these steps to complete this exercise:
- Navigate to https://www.bootstrapcdn.com/.
- From the main page, find the Quick Start block and copy the link that says Complete CSS.
- Open the
src/styles.css
file in the editor. - Add the following line at the end of the file:
@import url('');
- Paste the link you copied in step 2 inside the quotes of the
url( )
function. - Navigate to the Font Awesome page on BootstrapCDN.
- Copy the link to the CSS file.
- Add the following line at the end of the file:
@import url('');
- Paste the link to Font Awesome CSS inside the quotes of the
url( )
function:Figure 1.5: Import URLs
- Refresh the app in the browser:

Figure 1.6: Applying a different font to the application
As you can see, the font of the application got updated to a sans serif font, as that's the Bootstrap default.
Exercise 6: Using Bootstrap CSS and Font Awesome
In this exercise, we will update the template of AppComponent
to show that Font Awesome works. Follow these steps to complete this exercise:
- Open the
src/app.component.html
file and replace its content with the following:<h1 class="text-center mt-5"> <i class="fa fa-thumbs-up"></i> </h1>
- When the app refreshes, you should see the thumbs up icon in the center of the page:

Figure 1.7: The thumbs up icon
Activity 1: Using a BootSwatch Theme
We can change the default Bootstrap theme with a different one. The BootSwatch Themes project (https://www.bootstrapcdn.com/bootswatch/) provides a lot of colorful themes that are a drop-in replacement for Bootstrap. This means that all of the Bootstrap CSS selectors will work — they just look different! In this activity, we will use a different theme for our app.
The steps are as follows:
- Navigate to BootSwatch Themes (https://www.bootstrapcdn.com/bootswatch/) on BootstrapCDN.
- Select one of the themes and copy the link to the CSS.
- Update the link to Bootstrap CSS in
src/styles.css
. - Refresh the app in the browser and verify that the theme has been updated.
Note
The solution for this activity can be found on page 108.
Activity 2: Using Different Font Awesome Icons
Font Awesome comes with a large amount of icons that you can use once you've included the file. In this activity, we will use a different icon than the thumbs-up icon we have used already.
The steps are as follows:
- Open the
src/app/app.component.html
file. - Navigate to the Font Awesome icon list at https://fontawesome.com/v4.7.0/icons/.
- Replace the value of
fa-thumbs-up
with another icon. Note that you always need thefa
class. - Refresh the app in the browser and verify that the browser now shows your new icon.
Note
The solution for this activity can be found on page 109.
Creating the UI for the Application
One of the great things about working with Angular is that it promotes building applications in a modular and componentized way. In Angular, NgModule
(or simply Module
) is a way to group an application into logical blocks of functionality. A Module
is a TypeScript class with the @NgModule
decorator. In the decorator, we define how Angular compiles and runs the code inside the module.
In this chapter, we are going to build a module that groups together the components we want to use in the application's global user interface. We will create a LayoutComponent
that consists of a HeaderComponent
and a FooterComponent
, and in between those we will define the space where the actual application logic will be displayed:

Figure 1.8: Structure of our module
Creating the UiModule
In this section, we will generate the UiModule
using the ng
command, import the UiModule
in the AppModule
, and add Router Outlet
to the AppComponent
.
Exercise 7: Creating the UiModule
Using the ng generate
command, we can generate or scaffold out all sorts of code that can be used in an Angular application. In this exercise, we will use the ng generate module
command to generate the UiModule
. This command has one required parameter, which is the name. In this case, we use ui
. Follow these steps to complete this exercise:
- Open the terminal and navigate to the project directory.
- Run the ng generate module command from inside the project directory.
ng generate module ui CREATE src/app/ui/ui.module.ts (186 bytes)
As you can see by the output of the preceding command, the
UiModule
is generated in the new folder calledsrc/app/ui
.When we take a look at this file, we can see what an empty Angular module looks like:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [] }) export class UiModule { }

Figure 1.9: Generating the UI module
Exercise 8: Importing the UiModule
Now that the UiModule
has been created, we need to import it from the AppModule
. This way, we can use the code inside the UiModule
from other code that lives inside the AppModule
. Follow these steps to complete this exercise:
- In the editor, open the
src/app/app.module.ts
file. - Add the
import
statement at the top of the file:import { UiModule } from './ui/ui.module';
- Add a reference to
UiModule
in theimports
array inside theNgModule
decorator:@NgModule({ ... imports: [ // other imports UiModule ], ... })
The
UiModule
has now been created and imported in theAppModule
, which makes it ready to use:

Figure 1.10: Importing the UI module
Let's go ahead and create the first component inside the UiModule
to make it display in the app!
Exercise 9: Updating the AppComponent Template
When building an Angular app, you generally lean on Angular's router to tie all of the modules and components together. We will build all the application logic in modules and use the AppComponent
to display the current route.
For this to work, we need to update the AppComponent
template and define the router-outlet
component. Follow these steps to complete this exercise:
- In the editor, open the
src/app/app.component.html
file. - Remove all of its content and add the following tag:
<router-outlet></router-outlet>

Figure 1.11: Updating the template
After refreshing the app, we should see a blank page. This is because we don't have any routes set up, and thus there is no way that the Angular app knows what to display.
Let's move to the next topic so that we can create the basic layout.
Creating the Layout Component
In this section, you will use ng generate
to create the LayoutComponent
inside the UiModule
, add the LayoutComponent
to the AppRoutingModule
so that it gets displayed, and implement the template of the LayoutComponent
.
The LayoutComponent
is the main template of the application. The function of this component is to glue together the HeaderComponent
and the FooterComponent
and show the actual application pages in between those two.
Exercise 10: Generating the LayoutComponent
In this exercise, we will use the ng generate
command to create the LayoutComponent
. Follow these steps to complete this exercise:
- Open the terminal in the project directory.
- Run the following command from inside the project directory:
ng generate component ui/components/layout CREATE src/app/ui/components/layout/layout.component.css (0 bytes) CREATE src/app/ui/components/layout/layout.component.html (25 bytes) CREATE src/app/ui/components/layout/layout.component.spec.ts (628 bytes) CREATE src/app/ui/components/layout/layout.component.ts (269 bytes) UPDATE src/app/ui/ui.module.ts (273 bytes)
We can see that the component was created in the new
src/app/ui/components
directory:

Figure 1.12: Generating the layout component
The last line of the output shows us that the UiModule
got updated.
When we open the UiModule
in the editor, we can see that it added an import for the LayoutModule
and added it to the declarations
array in the NgModule
decorator.
Using declarations, we declare the existence of components in a module so that Angular knows that they exist and can be used:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { LayoutComponent } from './components/layout/layout.component'; @NgModule({ imports: [ CommonModule ], declarations: [LayoutComponent] }) export class UiModule { }

Figure 1.13: Declaring the component
Exercise 11: Adding the LayoutComponent to the AppRoutingModule
As described in the introduction of this section, we will use the LayoutComponent
as the base for the whole application. It will display the header, footer, and a router outlet to show the actual application screens. We will leverage Angular's built-in routing mechanism to do this. We will add a new route to the routing array and reference the LayoutComponent
in this route's component.
Follow these steps to complete this exercise:
- Open the
src/app/app-routing.module.ts
file. - Add an
import
statement to the list of imports at the top of the file:import { LayoutComponent } from './ui/components/layout/layout.component';
- Inside the empty array that is assigned to the
routes
property, we will add a new object literal. - Add the
path
property and set its value to an empty string,''
. - Add the
component
property and set its value to reference theLayoutComponent
that we just imported.The line of code that we must add to the
routes
array is as follows:{ path: '', component: LayoutComponent, children: [] , }
For reference, the complete file should look like this:
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { LayoutComponent } from './ui/components/layout/layout.component'; const routes: Routes = [ { path: '', component: LayoutComponent, children: [], } ] ; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }

Figure 1.14: Adding the LayoutComponent to the AppRoutingModule
When the application refreshes, we should see the text layout works!:

Figure 1.15: Layout component
Exercise 12: Implementing the LayoutComponent Template
In this exercise, we'll get rid of this default text and start implementing the template. Follow these steps to complete this exercise:
- Open the
src/app/ui/layout/layout.component.html
file. - Replace the contents of the file with the following code:
<h1>header placeholder</h1> <div class="container my-5"> <router-outlet></router-outlet> </div> <h1>footer placeholder</h1>
When we save the file, we will see that the browser outputs a blank page.
Looking in the Console tab from Chrome Developer Tools, we can see that we have an error stating Template parse errors: 'router-outlet' is not a known element:.
Figure 1.16: The router-outlet error
To make the
router-outlet
available to be used in theLayoutComponent
, we need to import theRouterModule
inUiModule
. - Open
src/app/ui/ui.module.ts
. - Add an
import
statement to the list of imports at the top of the file:import { RouterModule } from '@angular/router';
- Add a reference to the
RouterModule
inside theimports
array in theNgModule
decorator.
When we now save the file, we should see the placeholders for the header and footer, with some whitespace in-between and the router error gone from the console:

Figure 1.17: The header and footer placeholders
Now that that's done, let's add some content to the placeholders.
Creating the Header and Footer
In this section, you will download a logo to use in the application header, implement the header with a dynamic title and navigation items, and implement the footer with dynamic text.
Downloading the Angular Logo
We will now download the Angular logo and place it in the assets folder:
- Download the
https://angular.io/assets/images/logos/angular/angular.svg
file. - Save the file as
src/assets/logo.svg
in the project directory.
Exercise 13: Adding the Header to the LayoutComponent
In this exercise, we will add the header to LayoutComponent
. We will define three class properties: a string for the application logo, a title, and an array of objects that represent the navigation items we want to display in the header.
In the template, we will create a Bootstrap navbar
consisting of a nav
element with some styles, a link with the logo, the title, and the navigation items. Follow these steps to complete this exercise:
- In the editor, open the
src/app/ui/components/layout/layout.component.ts
file. - Inside the component class, we will add some new properties:
public logo = 'assets/logo.svg'; public title = 'Angular Social'; public items = [{ label: 'Posts', url: '/posts'}];
Figure 1.18: Adding the header
- In the editor, open the
src/app/ui/components/layout/layout.component.html
file. - Replace the contents of the header placeholder with the following markup:
<nav class="navbar navbar-expand navbar-dark bg-dark"> <a class="navbar-brand" routerLink="/"> <img [src]="logo" width="30" height="30" alt=""> {{title}} </a> <div class="collapse navbar-collapse"> <ul class="navbar-nav"> <li class="nav-item" *ngFor="let item of items" routerLinkActive="active"> <a class="nav-link" [routerLink]="item.url"> {{item.label}} </a> </li> </ul> </div> </nav>

Figure 1.19: The header markup
When we save this file and check in the browser, we will finally see the first part of the application being displayed:

Figure 1.20: The header
Exercise 14: Adding the Footer to the LayoutComponent
In this exercise, we will add the footer to the LayoutComponent
.
We will define two class properties, a string property for the name of the developer and the year.
In the template, we will create another Bootstrap navbar
consisting of a nav
element with some styles and the copyright message that uses both string properties we defined in our component class. Follow these steps to complete this exercise:
- In the editor, open the
src/app/ui/components/layout/layout.component.ts
file. - Inside the component class, we will add the following property. Don't forget to update the two placeholders with the right data:
public developer = 'YOUR_NAME_PLACEHOLDER'; public year = 'YEAR_PLACEHOLDER';
Figure 1.21: Adding the footer
- In the editor, open the
src/app/ui/components/layout/layout.component.html
file. - Replace the footer placeholder with the following markup:
<nav class="navbar fixed-bottom navbar-expand navbar-dark bg-dark"> <div class="navbar-text m-auto"> {{developer}} <i class="fa fa-copyright"></i> {{year}} </div> </nav>

Figure 1.22: The footer markup
When we save this file and check it in the browser, we will see that both the header and footer are being displayed:

Figure 1.23: The header and footer
We are done with the layout. Let's start building the actual application logic.
We can refactor the UiModule
by creating separate components for the header and the footer. The following activities should be completed using the knowledge that you have learned in this section.
Activity 3: Moving the Header to a Separate Component
In this activity, you will create a HeaderComponent
in src/app/ui/components/
. Reference the HeaderComponent
in the LayoutComponent
so that it says header works!.
After you have done this, you can copy the header markup and class properties from the LayoutComponent
to the HeaderComponent
.
The steps are as follows:
- Create a component called
HeaderComponent
. - Use the selector to reference the
HeaderComponent
from theLayoutComponent
. - Move the header markup from
layout.component.html
toheader.component.html
. - Move the header class properties from
layout.component.ts
toheader.component.ts
.Note
The solution for this activity can be found on page 110.
Activity 4: Moving the Footer to a Separate Component
In this activity, we will create a FooterComponent
, similar to and based on the instructions from the previous activity.
The steps are as follows:
- Create a component called
FooterComponent
. - Use the selector to reference the
FooterComponent
from theLayoutComponent
. - Move the footer markup from
layout.component.html
tofooter.component.html
. - Move the footer class properties from
layout.component.ts
tofooter.component.ts
.Note
The solution for this activity can be found on page 111.
Creating the App Logic
In this topic, we will build the actual logic of the application.
We will create the PostModule
, which contains all of the code related to displaying the posts that come from our API. Inside this module, we will add various components: a service and two resolvers. The components are used to display the data in the browser. We will go over their use in the next section. The service will be used to retrieve the data from the API. Lastly, we will add resolvers to the app that make sure the data from the service is available at the moment we navigate from one route to another.
Types of Components
In this topic, we will take a look at how we can differentiate our components by making a distinction between the container and presentational components. Sometimes, they are also called smart and dumb components when referred to how much knowledge of the world outside of the components each of them has.
The main difference we can make is this:
- A presentational component is responsible for how things look
- A container component is responsible for how things work
We will dive into more details of why this distinction is important when we create them, but we can give away a few things already.
Presentational components do the following:
- Get their data passed in using the
@Input()
decorator. - Any operations are passed up using the
@Output()
decorator. - Handle the markup and the styling of the application.
- Mostly just contain other presentational components.
- They have no knowledge (or dependencies) of any routes or services from the app.
Container components do the following:
- Retrieve their data from a service or a resolver
- Handle the operations that they receive from the presentational components
- Have very little markup and styling
- Will often contain both presentational and container components
The Folder Structure
To make this distinction clear in our project, we will use different folders for both types of components:
- The
src/<module>/components
folder is where the presentational components live. - The
src/<module>/containers
folder is where the containers components live.
Creating the Module
In this section, we will create a module called Post
. The Post
module is responsible for retrieving the posts from an API and showing them in the app.
In this chapter, you will generate the PostModule
using the ng
command and lazy load the PostModule
in the AppRoutingModule
.
Tip
You can use shortcuts for most ng
commands, for example, ng generate module
can be shortened to ng g m
.
Exercise 15: Generating the PostModule
We will use the ng generate module
command to generate the PostModule
.
This command has one required parameter name, and we will call this module post
. A second optional parameter, --routing
, is passed to create a file to hold the routes for this module, that is, the PostRoutingModule
. Follow these steps to complete this exercise:
- Open your terminal and navigate to the project directory.
- Run the following command from inside the project directory:
ng g m post --routing CREATE src/app/post/post-routing.module.ts (247 bytes) CREATE src/app/post/post.module.spec.ts (259 bytes) CREATE src/app/post/post.module.ts (271 bytes)
As you can see by the output of the preceding command, the PostModule
is generated in the new folder src/app/posts
.
Exercise 16: Lazy Loading the PostModule
In contrast to how we load the UiModule
by importing it into the AppModule
, we will lazy load this module using the AppRoutingModule
.
This is an optimization on how the application gets built, and it makes sure that the application has a smaller initial file to download by using a technology called code splitting. This basically bundles each lazy loaded module into its own file, and the browser is instructed to download this file when needed, but not before.
We will add two routes to the main application file. The first route is a route with a blank path
property (the default route), and its function is to redirect to the /posts
route.
The second route is the /posts
route, and it lazy loads the PostModule
. If the user navigates to the app, the first route that will be found is the blank redirect route. This will tell the router to navigate to /posts
. The router finds the /posts
route and navigates the user to that module. Follow these steps to complete this exercise:
- In the editor, open the
src/app/app-routing.module.ts
file. - Locate the existing
route
object that is defined in theroutes
property. - Inside the
children
array, we will create two routes that look like this:{ path: '', redirectTo: '/posts', pathMatch: 'full', }, { path: 'posts', loadChildren: './post/post.module#PostModule', },
Make sure that the complete routes property looks like this:
const routes: Routes = [ { path: '', component: LayoutComponent, children: [ { path: '', redirectTo: '/posts', pathMatch: 'full', }, { path: 'posts', loadChildren: './post/post.module#PostModule', }, ], } ];
We'll now see how this works:
- First, we define that we want to have children to the main route. This makes sure that all of the children get rendered in the
<router-outlet>
that is defined in theLayoutComponent
in the previous section. - We define the first route to respond to all paths (that's what the empty string does), and we make it redirect to the
/posts
route. - Lastly, we create a
posts
route and we tell it to load its children from the new module. TheloadChildren
property is what enables the lazy loading.
When we refresh the page, we can see that nothing changes in the app itself, but we can see that the URL has changed: it has redirected to /posts
:

Figure 1.24: The redirected URL
Let's move on to the next topic, where we will create the container components so that we can start seeing data.
Creating the Container Components
In this section, you will use ng generate
to create PostListComponent
and PostDetailComponent
inside the PostModule
, add routes to both components, and create TypeScript models for our data objects.
Exercise 17: Generating the PostListComponent
In this exercise, we will be using the ng generate
command to create our PostListComponent
. This is the component that will eventually list an overview for all our posts. The application route to this component will be /posts
. Follow these steps to complete this exercise:
- Open your terminal and navigate to the project directory.
- Run the following command from inside the project directory:
ng g c post/containers/post-list CREATE src/app/post/containers/post-list/post-list.component.css (0 bytes) CREATE src/app/post/containers/post-list/post-list.component.html (28 bytes) CREATE src/app/post/containers/post-list/post-list.component.spec.ts (643 bytes) CREATE src/app/post/containers/post-list/post-list.component.ts (280 bytes) UPDATE src/app/post/post.module.ts (368 bytes)
- Open the
src/app/post/post-routing.module.ts
file. - Import the
PostListComponent
:import { PostListComponent } from './containers/post-list/post-list.component';
- Add the following route to the
routes
array:{ path: '', component: PostListComponent, },
When we now refresh the page in the app, we should see the text post-list works! between our header and footer:

Figure 1.25: The PostListComponent
Exercise 18: Generating the PostDetailComponent
Very similar to the previous exercise, we will create the PostDetailComponent
. This is the component that will be responsible for displaying an individual post.
The application route to this component will be /posts/<id>
, where <id>
is the identifier of the post we want it to display. Follow these steps to complete this exercise:
- Open your terminal and navigate to the project directory.
- Run the following command from inside the project directory:
ng g c post/containers/post-detail CREATE src/app/post/containers/post-detail/post-detail.component.css (0 bytes) CREATE src/app/post/containers/post-detail/post-detail.component.html (30 bytes) CREATE src/app/post/containers/post-detail/post-detail.component.spec.ts (657 bytes) CREATE src/app/post/containers/post-detail/post-detail.component.ts (288 bytes) UPDATE src/app/post/post.module.ts (475 bytes)
- Open the
src/app/post/posts-routing.module.ts
file. - Import the
PostDetailComponent
:import { PostDetailComponent } from './containers/post-detail/post-detail.component';
- Add the following route to the
routes
array:{ path: ':id', component: PostDetailComponent, },
When the application refreshes and we navigate to http://localhost:4200/posts/42
, we should see the text post-detail works!:

Figure 1.26: The PostDetailComponent
Exercise 19: Defining our Data Model Types
To get the most out of working with TypeScript, we will create some custom types to describe the data we get back from the API. We can use these types throughout the app, and they will help us during development by providing type information. This will, for example, prevent us from trying to access properties that do not exist, and can help with auto completion in the editor.
In this application, we will use a post and profile. Follow these steps to complete this exercise:
- Open your terminal and navigate to the project directory.
- Run the following command from inside the project directory:
ng g class post/model/post CREATE src/app/post/model/post.ts
- Open the
src/app/post/model/post.ts
file and add the following content:export class Post { id: string; profileId: string; profile: Profile; type: 'text' | 'image'; text: string; date: Date; }
- Run the following command from inside the project directory:
ng g class post/model/profile CREATE src/app/post/model/profile.ts
- Open the
src/app/post/model/profile.ts
file and add the following content:export class Profile { id: string; avatar: string; fullName: string; posts?: Post[]; }
We have now defined the two models. The last thing we need to do is import the
Profile
model from ourPost
model, and vice versa. - Add
import { Post } from './post';
toprofile.ts
. - Add
import { Profile } from './profile';
topost.ts
:

Figure 1.27: Importing our model types
Creating a Service for API Interaction
While you could make a request to an API from a component, the best practice in Angular is to use services for retrieving and sending data from and to the API. The benefits of doing this are that services can be reused throughout multiple components; this keeps the component to its responsibility of displaying an interface.
An additional benefit is that it makes your code easier to test when writing unit tests. You can mock the behavior of a service to make sure that the unit tests are not dependent on the API being online at the moment the tests are run.
Once we have created the service, we can inject it into a component and use it.
Exercise 20: Using the Environment to Store the API Endpoints
In this exercise, we will use the environment of Angular CLI to store the API URL. Using the environment, we can define a different URL for development and production environments.
By default, the application generated with Angular CLI comes with two pre-defined environments. These environments are defined in angular-cli.json
in the default project.
Follow these steps to complete this exercise:
- Open the
src/environments/environment.ts
file. - Inside the
environment
variable, add a key calledapiUrl
and assign the value to the'http://localhost:3000/api'
string, which is the URL to the development API. - Open the
src/environments/environment.prod.ts
file. - Inside the
environment
variable, add a key calledapiUrl
and assign the value to the'https://packt-angular-social-api.now.sh/api'
string, which is the URL to the production API.
Exercise 21: Generating and Implementing the PostService
In this exercise, we will use the ng generate service
command to generate a service that will handle the interaction with the API. Follow these steps to complete this exercise:
- Open your terminal and navigate to the project directory.
- Run the following command from inside the project directory:
ng g s post/services/post CREATE src/app/post/services/post.service.spec.ts (362 bytes) CREATE src/app/post/services/post.service.ts (133 bytes)
The next step is to define two public methods in the
PostService
and make sure that these retrieve the data we need from the API. We will add two methods in thePostService
.The first method is the
getPosts
method, which does not take any arguments and returns anObservable
of all the posts from the API. The second method is thegetPost
method, which takes the ID of type string as an argument. It returns anObservable
of the post with the ID that is passed in as an argument, and includes all the posts that are made by that profile. - Open the
src/app/post/services/post.service.ts
file. - Add an
import
statement to import theHttpClient
from@angular/common/http
, a reference to the environment where we have the API URL defined, and thePost
model:import { HttpClient } from '@angular/common/http'; import { environment } from '../../../environments/environment'; import { Post } from '../model/post';
- Define the
baseUrl
anddefaultParams
constants:const baseUrl = `${environment.apiUrl}/posts/`; const defaultParams = 'filter[include]=profile';
- Update the constructor to inject the
HttpClient
and make it available under the privatehttp
variable:constructor(private http: HttpClient) { }
- Create a new method called
getPosts() {}
and add the following to it:public getPosts(): Observable<Post[]> { const params = `?${defaultParams}&filter[where][type]=text&filter[limit]=20`; return this.http.get<Post[]>(baseUrl + params); }
- Create a new method called
getPost(id)
and add the following to it:public getPost(id: string): Observable<Post> { const params = `?${defaultParams}`; return this.http.get<Post>(baseUrl + id + params); }
Exercise 22: Using the PostService in the Container Components
In this exercise, we will reference the PostService
in both the container components to fetch the data.
We will use the OnInit
component lifecycle hook provided by Angular to call into the injected service and invoke the methods from that service. Note that we do the same thing for both the PostListComponent
and the PostDetailComponent
. Follow these steps to complete this exercise:
- Open the
src/app/post/containers/post-list/post-list.component.ts
file. - Add an
import
statement for the newPostService
:import { PostService } from '../../services/post.service'; import { Post } from '../../model/post';
- Add a
public
class property calledposts
of typePost[]
:public posts: Post[];
- Update the constructor to inject the
PostService
and make it available under theprivate service
variable:constructor(private service: PostService) {}
- Add the following to the
ngOnInit
method:ngOnInit() { this.service.getPosts() .subscribe( res => this.posts = res, err => console.log('error', err), ) }
- Open the
post-list.component.html
file and update the content to the following:<pre> {{posts | json}} </pre>
Let's do the same for the
PostDetailComponent
now. - Open the
src/app/post/containers/post-detail/post-detail.component.ts
file. - Add an
import
statement for the newPostService
:import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; import { PostService } from '../../services/post.service'; import { Post } from '../../model/post';
- Add a
public
class propertypost
of typePost
:public post: Post;
- Update the constructor to inject the
PostService
andprivate route: ActivatedRoute
dependency:constructor(private route: ActivatedRoute, private service: PostService) {}
- Set the contents of the
ngOnInit
method to the following:this.service.getPost(this.route.snapshot.paramMap.get('id')) .subscribe( res => this.post = res, err => console.log('error' ,err) )
- Open the
post-detail.component.html
file and update the content to the following:<pre> {{post | json}} </pre>
Exercise 23: Importing the HttpClientModule to Enable the HttpClient
We are almost done creating the PostService
, but there is still one thing we need to fix. When we refresh the application, we can see that we have an error message in the console:
ERROR Error: StaticInjectorError[HttpClient] : StaticInjectorError[HttpClient] : NullInjectorError: No provider for HttpClient!

Figure 1.28: The import error
The reason that we get this error is because we have used the HttpClient
in the service, but Angular does not know where this module comes from. To fix this, we need to import HttpClientModule
in the AppModule
. Follow these steps to complete this exercise:
- Open the
src/app/app.module.ts
file. - Add an
import
statement to import theHttpClientModule
from@angular/common/http
:import { HttpClientModule } from '@angular/common/http';
- Update the
imports
array in theNgModule
decorator to importHttpClientModule
:@NgModule({ ... imports: [ ... HttpClientModule, ... ], ... })
When we refresh the application, we should see a list of posts retrieved from the API:

Figure 1.29: List of posts retrieved from the API
Let's continue and add some presentational components to give the posts some style.
Creating the Presentational Components
In this section, you will use ng generate component
to create the PostItemComponent
and PostProfileComponent
inside the PostModule
, implement the logic for these components, and use these components in our container components.
The PostItemComponent
accepts a single post as its input and displays that post. For displaying the profile that belongs to the post, we use the PostProfileComponent
. It takes the profile as input and uses the ng-content
component to project the content on top.
Exercise 24: Generating the PostItemComponent
In this exercise, we will use the ng generate
command to create our PostItemComponent
. Follow these steps to complete this exercise:
- Open your terminal in the project directory and run the following command:
ng g c post/components/post-item CREATE src/app/post/components/post-item/post-item.component.css (0 bytes) CREATE src/app/post/components/post-item/post-item.component.html (28 bytes) CREATE src/app/post/components/post-item/post-item.component.spec.ts (643 bytes) CREATE src/app/post/components/post-item/post-item.component.ts (280 bytes) UPDATE src/app/post/post.module.ts (574 bytes)
- Open the
src/app/post/components/post-item/post-item.component.ts
file. - Import
Input
from@angular/core
by adding it to the existingimport
statement and add the following:import { Post } from '../../model/post';
- Add the following property in the component class:
@Input() post: Post;
- Update the template to the following:
<div class="card"> <div class="card-body" *ngIf="post"> <app-post-profile [profile] ="post.profile"> <div class="my-2"> <a [routerLink] ="['/posts', post.id]" class="text-muted"> {{ post.date | date: 'medium'}} </a> </div> <p>{{post.text}}</p> </app-post-profile> </div> </div>
Exercise 25: Generating the PostProfileComponent
In this exercise, we will use the ng generate
command to create our PostProfileComponent
.
This component will display the avatar and full name of the profile that created the post, and it will use the ng-content
component to show the markup that exists inside the <app-post-profile>
tags from the previous exercise. Follow these steps to complete this exercise:
- Open the terminal and run the following command from inside the project directory:
ng g c post/components/post-profile CREATE src/app/post/components/post-profile/post-profile.component.css (0 bytes) CREATE src/app/post/components/post-profile/post-profile.component.html (31 bytes) CREATE src/app/post/components/post-profile/post-profile.component.spec.ts (664 bytes) CREATE src/app/post/components/post-profile/post-profile.component.ts (292 bytes) UPDATE src/app/post/post.module.ts (685 bytes)
- Open the
src/app/post/components/post-profile/post-profile.component.ts
file. - Import
Input
from@angular/core
by adding it to the existingimport
statement and add the following:import { Profile } from '../../model/profile';
- Add the following property to the component class:
@Input() profile: Profile;
- Update the template to the following:
<div class="media" *ngIf="profile"> <img class="avatar mr-3 rounded" [attr.src]="profile.avatar" [attr.alt]="profile.fullName"> <div class="media-body"> <h5> {{profile.fullName}} </h5> <ng-content></ng-content> </div> </div>
- Open
src/app/post/components/post-profile/post-profile.component.css
and add the following styles:img.avatar { height: 80px; width: 80px; }
Exercise 26: Using the PostItemComponent
In this exercise, we will use the PostItemComponent
. Follow these steps to complete this exercise:
- Open the
src/app/post/containers/post-list/post-list.component.html
file. - Update the template to the following:
<div class="row"> <div class="col-md-8 offset-md-2 mb-3" *ngFor="let post of posts"> <app-post-item [post]="post"></app-post-item> </div> </div>
- Open the
src/app/post/containers/post-detail/post-detail.component.html
file. - Update the template to the following:
<app-post-item [post]="post"></app-post-item>
When we now refresh the application in our browser, we can see that the content is styled and that the navigation still works as expected:

Figure 1.30: List of styled posts
We have successfully separated the concerns of retrieving the data and displaying it.
Resolving Data Using the Router
In this section, you will manually create two injectable classes that act as resolvers, configure the router to use these resolvers, and update the container components to use this resolved data.
A resolver is a class that we can use to fetch the data that we use in the component before the component is displayed. We call the resolvers in the routes where we need the data. In the implementation, the resolvers retrieve the data from the API and return it so that it can be displayed in the components.
Note
More information about resolvers can be found at https://angular.io/guide/router#resolve-pre-fetching-component-data.
Our application is quite neatly structured already, but there is one thing that we can optimize.
To see what the problem is, open Chrome Developer Tools and open the Performance tab. Hit the Cog icon and set Network to Slow 3G. If we now click around in the application, we will see that that the page navigation still works, but we are presented with empty pages.
The reason for this is that while the components are loaded correctly, they still need to retrieve the data after they are loaded. This is because the components call into the PostService
from the ngOnInit
method.
It would be better if the router could make sure that the component has all the necessary data loaded before entering the page. Fortunately, the Angular router provides a way to handle this by using resolvers. They will resolve the data before entering the route, and in the component, we can just take this resolved data and display it.
The resolvers that we create need the @Injectable()
decorator to make sure that they are part of the dependency injection in Angular.
Exercise 27: Creating a Resolver for the getPosts Method
In this exercise, we will create a resolver that invokes the getPosts()
method defined in the PostService
. Follow these steps to complete this exercise:
- Open a terminal and run the following command:
ng g class post/resolvers/posts-resolver
- Open the
src/app/post/resolvers/posts-resolver.ts
file. - Start the file by defining the necessary imports:
import { Injectable } from '@angular/core'; import { Resolve } from '@angular/router'; import { Post } from '../model/post'; import { PostService } from '../services/post.service';
- Decorate the
PostsResolver
class with the@Injectable
operator:@Injectable({ providedIn: 'root' }) export class PostsResolver {}
- Make the class implement
Resolve<Post[]>
:@Injectable({ providedIn: 'root' }) export class PostsResolver implements Resolve<Post[]> { }
- Inside the class, create a constructor and inject the
PostService
:constructor(private service: PostService) {}
- Below the constructor, create a class method called
resolve
and make it return thegetPosts()
method from thePostService
:resolve() { return this.service.getPosts(); }
This is the resolver that will be used to retrieve all the posts, just like how we do this currently in the PostListComponent
.
Exercise 28: Creating a Resolver for the getPost Method
In this exercise, we will create a resolver that invokes the getPost()
method defined in the PostService
. We will pass in the ID that we get from the ActivatedRouteSnapshot
. Follow these steps to complete this exercise:
- Open a terminal and run the following command:
ng g class post/resolvers/post-resolver
- Open the
src/app/post/resolvers/post-resolver.ts
file. - Start the file by defining the necessary imports:
import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Resolve } from '@angular/router'; import { Post } from '../model/post'; import { PostService } from '../services/post.service';
- Decorate the
PostResolver
class with the@Injectable
operator and pass in an object with theprovidedIn
key set toroot
:@Injectable({ providedIn: 'root' }) export class PostResolver {}
- Make the class implement
Resolve<Post>
:@Injectable({ providedIn: 'root' }) export class PostResolver implements Resolve<Post> { }
- Inside the class, create a constructor and inject the
PostService
:constructor(private service: PostService) {}
- Below the constructor, create a class method called
resolve
, and pass theroute: ActivatedRouteSnapshot
class into it:resolve(route: ActivatedRouteSnapshot) { }
- Inside the
resolve
method, we return thegetPost()
method from thePostService
while getting theid
parameter from theActivatedRouteSnapshot
:resolve(route: ActivatedRouteSnapshot) { return this.service.getPost(route.paramMap.get('id')); }
This is the resolver that will be used to retrieve the posts that we have navigated to in the route.
Exercise 29: Adding the Resolvers to the PostRoutingModule
In this exercise, we will add the two new resolvers to the PostsRoutingModule
. We will do this by importing the resolvers and then adding a resolve
property to both of the routes. The resolve
property takes an object where the key is how the data will be available in the router after it is resolved, and the value is a reference to the imported resolver. Follow these steps to complete this exercise:
- Open the
src/app/post/post-routing.module.ts
file. - Import the two freshly created resolvers:
import { PostsResolver } from './resolvers/posts-resolver'; import { PostResolver } from './resolvers/post-resolver';
- Update both the routes to add a
resolve
property and call into the resolvers:const routes: Routes = [ { path: '', component: PostListComponent, resolve: { posts: PostsResolver, } }, { path: ':id', component: PostDetailComponent, resolve: { post: PostResolver, } }, ];
If we check the Network tab in Chrome Developer Tools, we can see that we make two requests to the same endpoint. This is because we retrieve the data twice: once in the resolver and once in the component. Let's update the container components and let them use the data resolved by the router.
Exercise 30: Using Resolved Data in the PostListComponent
In this exercise, we will update the PostListComponent
to read the data that has been resolved by the router. We will subscribe to the data of the active route and we will map over that data twice. In the first map
command, the posts
value relates to the object key we used in the resolver object for this route. Follow these steps to complete this exercise:
- Open the
src/app/post/containers/post-list/post-list.component.ts
file. - Import
ActivatedRoute
from@angular/router
:import { ActivatedRoute } from '@angular/router'; import { map } from 'rxjs/operators';
- Remove the
PostService
import as we are no longer going to use it here. - Update the constructor to inject only
private route: ActivatedRoute
:constructor(private route: ActivatedRoute) { }
- Update the
ngOnInit()
method and replace the content with the following code:ngOnInit() { this.route.data .pipe( map(data => data['posts']), ) .subscribe( res => this.posts = res, err => console.log('error', err), ); }
Refresh the page and make sure that the data is still loaded.
Exercise 31: Using Resolved Data in the PostDetailComponent
In this exercise, we will update the PostDetailComponent
to read the data that has been resolved by the router. We subscribe to the data of the active route and we will map over that data. In the map
command, the profile
value relates to the object key we used in the resolver object for this route. Follow these steps to complete this exercise:
- Open the
src/app/post/containers/post-detail/post-detail.component.ts
file. - Add the following
import
statement:import {map} from 'rxjs/operators';
- Remove the
PostService
import as we are no longer going to use it here. - Update the constructor to only inject
private route: ActivatedRoute
:constructor(private route: ActivatedRoute) { }
- Update the
ngOnInit()
method and replace the content as follows:ngOnInit() { this.route.data .pipe( map(data => data['post']) ) .subscribe( res => this.post = res, err => console.log('error', err), ); }
Refresh the page and make sure that the data is still loaded.
In the following activities, we will introduce the ProfileModule
, which is responsible for listing the profiles. The following activities should be performed using the knowledge that you have learned in this chapter.
Activity 5: Creating a ProfileModule
In this activity, you will create a ProfileModule
in src/app/profile
. Add a menu item in the LayoutModule
to link to the new ProfileModule
.
The steps are as follows:
- Create a module called
ProfileModule
. - Define the
/profiles/
route to lazy load this new module inapp-routing.module.ts
. - Add a menu item to link to the
/profiles/
URL in theheader.component.ts
file created in Activity 3.Note
The solution for this activity can be found on page 113.
Activity 6: Creating Container Components
In this activity, we will create the container components ProfileListComponent
and ProfileDetailsComponents
. The routes are similar to those in the PostModule
.
The steps are as follows:
- Add the
ProfileListComponent
andProfileDetailComponent
containers. - Add routes to the container components in
ProfileRoutingModule
.Note
The solution for this activity can be found on page 114.
Activity 7: Creating Service and Resolvers
In this activity, we will create the service and resolvers called ProfileService
, ProfilesResolver
, and ProfileResolver
. The functionality of those services and resolvers is identical to those in the PostModule
.
The steps are as follows:
- Add a
ProfileService
to retrieve the data. - Add a
ProfilesResolver
andProfileResolver
and use them in theProfileRoutingModule
.Note
The solution for this activity can be found on page 115.
Activity 8: Creating Presentational Components
In this activity, we will create the presentational component to display the profile data.
The steps are as follows:
- Use the resolved data in the container components.
- Create the presentational components to display the profile data from the API.
Note
The solution for this activity can be found on page 117.
Summary
We started this chapter by installing Angular CLI and creating a new application. We configured styles using Bootstrap and Font Awesome. We then created the UI for our application, and we created the layout module and then the header and footer components. We finished this chapter by creating the application logic, including creating the container and presentational components, a service for API interaction, and routers.
Our basic application has been built, and even though there are enough things to add and optimize, it's well-structured and works using Angular's best practices. In the next chapter, we will add support for Server-Side Rendering by adding Angular Universal.