0% found this document useful (0 votes)
1K views

Angular From Scratch

Uploaded by

Vineeth Babu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views

Angular From Scratch

Uploaded by

Vineeth Babu
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 88

Angular from Scratch

A friendly guide for absolute beginners

Ajdin Imsirovic
This book is for sale at http://leanpub.com/angular-from-scratch

This version was published on 2021-10-09

This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.

© 2021 Ajdin Imsirovic


Contents

Chapter 0: Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Software we’ll be using . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What is Angular? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Let’s Build the Simplest Possible Angular App . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Viewing our Angular app in the browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Re-visiting Angular versioning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Updating our Angular version automatically . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

Chapter 1: Inspecting the Boilerplate Angular App . . . . . . . . . . . . . . . . . . . . . . . . . 8


1.1. Revision: things to do before running ng new ... . . . . . . . . . . . . . . . . . . . . . . 8
1.2 What happens when we run the ng new ... command? . . . . . . . . . . . . . . . . . . . 9
1.3. What are the contents of the Angular boilerplate app? . . . . . . . . . . . . . . . . . . . . 9
1.3. Inserting an Angular app into index.html . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.4 Tracking our project with Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

Chapter 2: Generating components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23


2.1 Adding the Navigation Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.2 Updating the CSS of the app component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.3 Using the :host selector in the app.component.css file . . . . . . . . . . . . . . . . . . . . 36

Chapter 3: Writing an Angular component from scratch . . . . . . . . . . . . . . . . . . . . . . 39


3.1 Writing the ProfileComponent from scratch . . . . . . . . . . . . . . . . . . . . . . . . . . 39
3.2 Adding global styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

Chapter 4: Using Routing and Adding a Login Component . . . . . . . . . . . . . . . . . . . . 43


4.1 Showing the Profile Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.2 Adding Routes to app-routing.module.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.3 Adding a login component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

Chapter 5: Binding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.1 Binding Template Files to Class Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.2 Binding events in Angular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
5.3 Binding a (click) event to AppComponent template file . . . . . . . . . . . . . . . . . . . . . 54
5.4 Defining the randomColor function inside app.component.ts . . . . . . . . . . . . . . . . 55
5.5 Property binding in Angular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
CONTENTS

5.5.1 Dynamically update HTML attributes using property binding and method calls . . . 59
5.6 Binding a property to a button click . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
5.7 Comparing one-way and two-way data binding in Angular . . . . . . . . . . . . . . . . . 65
5.8 Examining Property Bindings in Angular in More Detail . . . . . . . . . . . . . . . . . . 66

Chapter 6: Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.1 Adding a service to our app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6.2 Working with HttpClient . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

Chapter 7: Revision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
A revision of things we’ve learned . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
A revision of things we glossed over . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Explanation of the reason why this book was written the way it was . . . . . . . . . . . . . 83
Additional explanation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
What’s next? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Chapter 0: Introduction
Software we’ll be using
The software (the Operating System) that is being used in this book is the current, newest stable
version of Ubuntu Linux.
The reason for this choice:

• I have a Windows machine too. For many years, Windows didn’t support Ruby and Ruby on
Rails. It was a frustrating experience to “fight the OS” using varios workaround. Finally, I just
gave it up.
• A vast majority of servers are run on Linux. We, as web developers, will inevitably be faced
with having to do some work on the server. Getting used to working with Linux is very useful
and prepares us for our future work.
• Linux command line and Mac OS command line are quite similar.
• I’m more comfortable using Linux than Windows.

With all of this being said, it’s likely that you’ll be able to follow along using Windows just fine.
Still, I don’t test my code and my development setup on Windows, so I’ll leave it at that.

What is Angular?
Angular is a grouping of organized, pre-built code, that helps us build websites in a specific,
streamlined manner.
It’s a way to control the complexity of building a website - a tool we can wield to tame our web
development processes.
Of course, it’s not the only tool that we can use. There are many others, like: Vue, React, jQuery,
Ember, Alpine.js, Svelte, etc.
There are actually two separate versions of Angular:

• the “old” Angular (versions 1.x), called AngularJS


• the “new” Angular (versions 2+), simply called Angular
Chapter 0: Introduction 2

This book (and the other Angular books in this series) deals with this “new” version of Angular.
Every six months, a new version of Angular comes out - currently, it’s at version 12.
Interesting note: to match the versions of the Angular router and Angular core, the version 3 was
completely skip. So the Angular 2+ history goes like this (version-wise):

• Angular 2
• Angular 4
• Angular 5
• …

As far as support goes, there are 6 months of full support for the currently-issued version of Angular,
then after a new version comes out, the previous version is supported for another 12 months (it’s
called LTS - Long Term Support).
TL; DR: Keep your Angular up-to-date, if at all possible.
Sometimes, updating is as easy as running ng update command - which auto-updates the code
inside your Angular app. The idea is to make this process as painless as possible, hopefully without
the need for manual fixes by us, the users of the framework.
Also, since the release cycle is so quick, there are usually no major changes from one version to the
next - it’s simply not possible to make too many major updates to a framework in such a short time
- even though the Angular team at Google is relatively large.

Let’s Build the Simplest Possible Angular App


To work with Angular, we must have Node.js and npm installed on our machine.
If you have no idea what Node.js and NPM are, and what they are for, you can read an in-depth
tutorial on the subject, titled Understanding Node.js, NPM, and JavaScript modules¹.
Before we begin, we need to make sure we have Node and npm installed, with:

1 node --version & npm --version

If Node.js and NPM are installed, we’d get back something like the following:

1 v14.16.0
2 7.11.1
¹https://www.codingexercises.com/guides/understanding-node-npm-and-javascript-modules
Chapter 0: Introduction 3

Of course, versions can be different - it’s best to be up to date, which, currently, is version 14 of
Node.js.
If you need to either install Node.js on your machine, or update to a newer version, please refer to
my article on codingexercises.com, titled: The Proper Way to Install Node.js on Ubuntu².
Now that we’ve got everything we need to get started, installing Angular is easy:

1 npm install -g @angular/cli

Once Angular is installed, you can generate a new Angular project like this:

1 mkdir angulartestapp && cd angulartestapp && ng new angulartestapp

Angular CLI will prompt us with this question:

1 ? Would you like to add Angular routing?

We don’t want angular routing, so we’ll type an n.


We’ll accept the default CSS option by pressing the RETURN (ENTER) key.
That’s all we need to do for now.
Here’s the output in the command line:
²https://www.codingexercises.com/proper-way-to-install-nodejs-on-ubuntu
Chapter 0: Introduction 4

Output of running ng new in the command line

Let’s now open it in VS code using this command:

1 code .

Note: if you don’t have VS Code on your computer you can download it here³.
Alternatively, you can use any other code editor, but in this book I’ll be using VS Code.
You might notice that the opened VS Code is showing a single folder in the sidebar panel, and the
folder reads: angulartestapp.
This means that when we ran this command:

1 mkdir angulartestapp && cd angulartestapp && ng new angulartestapp

… what happened was the following:

1. A new folder was made, and it was named angulartestapp


2. … we then cd’ed into it
3. .. then we ran the ng new angulartestapp command, which built our new Angular app, putting
it inside another angulartestapp folder.

Knowing what we know now, we could have ran this command instead:
³https://code.visualstudio.com/
Chapter 0: Introduction 5

1 mkdir angularplayground && cd angularplayground && ng new angulartestapp

Then we’d have the folder angularplayground holding our angulartestapp and down the line, if we
wanted to have another angular app in a separate sub-folder inside angularplayground, we’d just
run the command:

1 ng new someothername

Obviously, someothername would need to be a bit more meaningful name for our different Angular
app.
Still, I chose to do it like this so that you remember how this kind of setup works.
In this introduction, we won’t go into any other details. For now, let’s just serve our Angular app
(meaning: let’s make it appear in the browser).
We’ll do it by running:

1 ng s

We could have ran the full ng serve command, but honestly, why bother when we have this handy
shortcut command.
Here’s the output of running ng s in the console:

Output of running ng s in the command line


Chapter 0: Introduction 6

Viewing our Angular app in the browser


To view our Angular app in the browser, we can open any modern browser (Chrome, Firefox, Edge,
etc.) and we can just follow the instructions in the console output.
In other words, we need to access the following URL from the browser’s address bar:

1 localhost:4200

Here’s what our app looks like in the browser at the moment.

Output of running ng s in the command line

Re-visiting Angular versioning


Let’s quickly check our current version of Angular, using the following command:

1 ng --version

The above command outputs the following:


Chapter 0: Introduction 7

Output of checking our version of Angular

Let’s now use ng update to see how that works.

Updating our Angular version automatically


Before we run the ng update command, let’s first stop our Angular server from the command line,
by simply pressing the CTRL c keyboard combination.
We’ll run ng update again. Here’s what we get:

The result of running the “ng update” command

Let’s now check our Angular version again:

1 ng --version

We get the same output as before, which means we’re at the most-recent version.
In the next chapter, we’ll learn about the basic building blocks of Angular.
Chapter 1: Inspecting the Boilerplate
Angular App
In this chapter, we’ll discuss the following topics:

1. Revision: Things to do before running ng new ...


2. What happens when we run ng new ...?
3. What are the contents of the boilerplate Angular App?
4. How to insert an Angular app into index.html and why should we do it

1.1. Revision: things to do before running ng new ...


Let’s say you are using a brand new machine.
We’ve already described the following steps in the previous chapter, so this is just a quick revision.
As the old Romans used to say: “Repetition is the mother of knowledge”.

Step 1: Make sure you have Node.js and NPM installed


1 node --version;
2 npm --version

If both return newer versions, you have the prerequisites.

Step 2: Test whether you have Angular installed


Run:

1 ng --version

If it’s not installed, run:

1 npm install -g @angular/cli

Step 3: Generate a new Angular project and answer the prompts


Once Angular is installed, you can generate a new Angular project like this:
Chapter 1: Inspecting the Boilerplate Angular App 9

1 ng new my-app

#### Step 3.1: Routing?


Angular CLI will prompt us with this question:

1 ? Would you like to add Angular routing?

This time, we do want angular routing, so we’ll type a y.

Step 3.2: Stylesheet?

Next, Angular CLI will ask us which stylesheet format we’d like to use, and we can just press the
ENTER key to accept the default CSS option.

1.2 What happens when we run the ng new ...


command?
Besides the above prompts by the Angular CLI, a couple of other important things happen when we
run the ng new <app name> command:

• We get an entire copy of the Angular framework and all its dependencies installed inside our
<app name> directory. These dependencies get added to the node_modules sub-directory of our
project. In our example app, we’ve named it my-app so the Angular framework is saved inside
my-app/node_modules.
• A barebones Angular app gets installed inside the ./src/app folder.

Next, we’ll inspect this boilerplate, skeleton app that just got generated.

1.3. What are the contents of the Angular boilerplate


app?
The minimal Angular project (which we get when we run the ng new command) lives inside the
./src/app folder.

Inside the src/app folder, Angular CLI generated the following files for us:
Chapter 1: Inspecting the Boilerplate Angular App 10

The structure of Angular-generated app component

Some other files and folders get generated too, but they are not important for our discussion.
We need to understand how the files that got generated in ./src/app folder work together.
To be able to have a better understanding let’s rearrange these generated files by order of importance.
We’ll also give all these files some “nicknames”:

• app.component.ts (aka the “Class” aka “C”)


• app.component.html (aka the “Template”, which we’ll further abbreviate to “TPL”)
• app.component.css (which we’ll simply refer to as “CSS”)
• app-routing.module.ts (aka the “Module”, or even shorter: “MDL”)
• app.component.spec.ts (this file is for testing, and we’ll skip it for now)
• app.module.ts (aka “Routing Module”, or even shorter: “RMDL”)

Now we can turn the entire list of files above, into a simple diagram:
Chapter 1: Inspecting the Boilerplate Angular App 11

A diagram of app folder’s starter files

What we’ve just done here is:

• We’ve stripped away the complexity of the ./src/app folder,


• We’ve made it easier to understand the contents of the ./src/app folder using a simple image

Feel free to print out the above diagram and keep it above your monitor. It’s going to to wonders for
understanding how things fit together while we’re at the very beginning of working with Angular.
We’ll be referring back to this diagram again and again throughout this chapter.
Next, we’ll discuss how each of these files work together.

1.3.1 How the files inside ./src/app work together


To better understand how the files inside ./src/app work together, we’ll need to inspect the contents
of each of the generated files.
We’ll begin by looking into the Class file (i.e the app.component.ts file).

1.3.1.1 The Class file (the app.component.ts file)

Here is the contents of the Class file (i.e the app.component.ts file). We’ve added some additional
visual cues to make it easier to see how everything fits together.
Chapter 1: Inspecting the Boilerplate Angular App 12

The contents of the class file in Angular’s app component

Here’s the explanation of the Class file, line by line:

• On line 1, the Component functionality gets imported from @angular/core


• On lines 3-7, the @Component decorator is given a few properties inside an object literal. The
object literal is everything that we see between the {} (that is, between the curly brackets). The
role of the @Component decorator is to add some meta information related to our component,
namely, the selector, the templateUrl, and the styleUrls
• On line 5, we set the location of the TPL file (the Template HTML file for our App Component),
• On line 6, we set the location of our App Component’s CSS file
• On lines 8-10, we export the AppComponent class, so that this class can be used elsewhere in our
app.

To reiterate, this is what the Class file does:

• It defines some meta information for the AppComponent inside the @Component decorator.
• It exports the AppComponent class to make it available to other parts of our app.
Chapter 1: Inspecting the Boilerplate Angular App 13

Additionally, the Class file defines all the logic for our component. Currently, there is no logic.
Instead, only the title property is set to my-app, but there are no methods inside our class
whatsoever.
Notice also that this file does several things in order:

• import
• decorator
• class export

This import-decorator-export file structure is common throughout Angular, as we’ll see later on in
this book.

1.3.1.2 The Template file (the app.component.html file)

Next, we’ll look at the template file.


Angular added quite a lot of code inside. Worry not, though, soon, we’ll remove most of it.
Here’s the full contents of this file:
The contents of the full boilerplate app.component.html file⁴
All of the code in this file is what gets rendered in our browser.
The most important part is the <router-outlet></router-outlet> code on line 501.
But let’s not get ahead of ourselves. Instead, let’s delete most of the code from this file, and replace
it with the following code:

1 <!-- The content below is only a placeholder and can be replaced -->
2 <div style="text-align: center">
3 <h1>
4 Welcome to {{ title }}!
5 </h1>
6 </div>
7
8 <router-outlet></router-outlet>
⁴https://gist.github.com/ImsirovicAjdin/bd2b65218115c7f54458e411521f76a3
Chapter 1: Inspecting the Boilerplate Angular App 14

The updated contents of the app component’s template file

Now that we’ve simplified our code, we can see more obviously that it’s just mostly regular HTML.
However, there are a couple additional things that are not the usual HTML:

1. The Welcome to {{ title }}! code on line 4


2. The <router-outlet></router-outlet> code on line 8

The <router-outlet> is simply a placeholder that will mount into the DOM whatever component
is set to be placed on a certain route. More about that later. For now, let’s discuss the title.
In a nutshell, the title variable is displayed on the screen using what’s commonly known as
variable interpolation. Many languages and frameworks other than Angular also employ variable
interpolation extensively.
In this specific case, the title is the variable that’s made available by our component’s Class file
(i.e app.component.ts), and we can use it inside our template file (i.e app.component.html).
Whatever we set as the title inside our Class, will be displayed between these double curly brackets.
The {{ }} syntax is commonly known as “mustache” syntax. Some refer to it as “a template
expression”. It’s one of the simplest ways to get some data from the Class to the template in Angular.
Before we continue, we’ll take a look at our updated app being served in the browser.
Chapter 1: Inspecting the Boilerplate Angular App 15

1.2.1.2.1 Viewing the default app

To view the default app that was created by ng new my-app command, we need to go back to our
command line and first change into the app directory with this command:

1 cd my-app

Next, we’ll serve our Angular app with:

1 ng serve

To view the barebones Angular app served in the browser, we’ll open the following URL:
localhost:4200.

Here’s the screenshot of our app as it is right now:

The updated my-app app served in the browser

1.2.1.3 The CSS file of AppComponent

The CSS file of App Component is currently empty. At this point of our examination of the default
barebones app, we will not add any changes to it. The only important thing to note about the CSS
file for our App Component is that whatever CSS properties we specify in this CSS file, those CSS
properties will be applied only to the App Component.
Next, we’ll discuss the app.module.ts file (the file that we dubbed “MDL”).

1.2.1.4 Understanding the app.module.ts file

The app.module.ts file, the one that we called MDL in our diagram, has three distinct sections:

• the import
Chapter 1: Inspecting the Boilerplate Angular App 16

• the @NgModule decorator section


• the export section

Here is the contents of the app.module.ts file, with the above three sections marked in magenta
squares:

The three distinct sections of the MDL file

The first section, the one with the import statements, is grouped into two sub-sections with two
imports each.
Chapter 1: Inspecting the Boilerplate Angular App 17

The first sub-section is NgModule. The official documentation provides an in-depth explanation of it.
A simplified explanation is that an @NgModule is a decorator.
The second sub-section imports the BrowserModule.
As can be read in the official docs, the BrowserModule exports all the required infrastructure for
all Angular apps. To be more specific, the BrowserModule gives us some browser-specific services
including DOM rendering and sanitization.
We’ve seen a decorator earlier, when we discussed the app.component.ts file. The decorator we
discussed there was the @Component decorator.
Similar to the @Component decorator, any other decorator - including the @NgModule decorator, takes
a metadata object.
In the case of the @NgModule decorator inside the app.module.ts file, this @NgModule decorator
describes how to compile the App Component. It basically serves to describe how the entire app’s
“plumbing” works, as it lists out all the necessary parts: declarations, imports, providers, and
bootstrap (the entry or root) component.

After we’ve imported the BrowserModule and the @NgModule, we are also importing the following
two modules:

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


• import { AppComponent } from './app.component';

What the above code does is:

1. It imports the AppRoutingModule from the app-routing.module file


2. It imports the AppComponent from the app.component.ts file

With that, we now understand what the first section of the app.module.ts file does: it simply imports
all the things we will need to pass to the metadata object (the object literal) inside the @NgModule in
the second section of the file.
Here’s the code of the second section of the app.component.ts file:

1 @NgModule({
2 declarations: [
3 AppComponent
4 ],
5 imports: [
6 BrowserModule,
7 AppRoutingModule
8 ],
9 providers: [],
10 bootstrap: [AppComponent]
11 })
Chapter 1: Inspecting the Boilerplate Angular App 18

As we can see in the code above, we specified four keys inside the metadata object. They all describe
all the components, modules, data providers, adn the entry point for the app.module. Specifically:

• declarations specifies all the components our app.module uses


• imports specifies all the modules our app.module uses
• providers specifies all the data providers - we don’t need to understand this just yet
• bootstrap specifies the root component that Angular will insert into the index.html file, which
will be served in our app

The third section of app.module.ts is the export statement, where we’re exporting the AppModule
class.
Next, we’ll look into our app routing module.

1.2.1.5 Understanding the app-routing.module.ts file


Before we can even start talking about the structure of the app-routing.module.ts file, we need to
discuss the router imports.
The Router is a service. It is used to show a specific component template under a URL that we
specify. In the image below, we can find the Router imports on line 2, right under the NgModule
import.
Chapter 1: Inspecting the Boilerplate Angular App 19

The structure of the app routing module ts file

After the imports, we specify the routes constant, which is currently an empty array, but we’ll soon
add to it.
The @NgModule decorator’s metadata object literal comes with two entries: imports and exports.
Finally, we just export the AppRoutingModule class.
Next, we’ll look at where and how our Angular app gets injected inside the index.html file.

1.3. Inserting an Angular app into index.html


Let’s step outside the ./src/app folder and find the index.html file in our project’s tree structure:
Chapter 1: Inspecting the Boilerplate Angular App 20

The index html file is the entry point for our Angular app

Let’s examine the contents of the index.html file.

1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8">
5 <title>MyApp</title>
6 <base href="/">
7
8 <meta name="viewport" content="width=device-width, initial-scale=1">
9 <link rel="icon" type="image/x-icon" href="favicon.ico">
Chapter 1: Inspecting the Boilerplate Angular App 21

10 </head>
11 <body>
12 <app-root></app-root>
13 </body>
14 </html>

Inside the above code we can see a custom <app-root> tag. This is the tag into which the entire
Angular app will get mounted.
While our Angular app is open in the browser, we can press the F12 key to open the developer tools.
On the Elements tab, we can see the updated DOM structure of our web page. Notice that our entire
Angular app is inserted into the <app-root> tag.

We can see the effects of the mounted app using the developer tools

We’ve already covered all of this, but now is a good time to reiterate how our app gets mounted:
1. Inside the ./src/app folder, the app.module.ts file combines all the plumbing of the Angular
framework. It lists the metadata for our AppModule inside the @NgModule decorator, and specifies:
* the declarations (i.e components),
* the imports (i.e other modules it needs),
* the providers (i.e the sources of data), and
* the bootstrap file (which is the AppComponent file)
2. The bootstraped AppComponent is the name of the class we’ve exported at the very bottom of the
app.component.ts file. The app.component.ts file has its own metadata object literal passed inside
the @Component decorator. The first entry inside the @Component decorator is the custom HTML tag
for our AppComponent. This is the selector entry, and its value is set to app-root.
In a nutshell, this is how our Angular app gets loaded into the index.html file. In turn, this file gets
loaded into the browser at localhost:4200 when we run the ng serve command.
Chapter 1: Inspecting the Boilerplate Angular App 22

We’ve covered the contents of the generated app folder, and the index.html file in the very root of
our project.

1.4 Tracking our project with Git


If you’re familiar with Git, there are two good things to note:

• first, every ng new ... app comes with Git installed and, once the boilerplate app is ready, the
first commit is made, with the commit message of “Initial commit”
• second, I’ve tried my best to keep all the progress in our book in nicely-organized commits. This
project’s history is available at the following URL: https://github.com/ImsirovicAjdin/angular-
book-1⁵

That wraps up this chapter.


In the next chapter, we’ll add our site’s navigation, using the built-in component generator.
⁵https://github.com/ImsirovicAjdin/angular-book-1
Chapter 2: Generating components
In this chapter, we’ll cover:
2.1 Adding the Navigation Component
2.2 Moving the HTML of the App Component

2.1 Adding the Navigation Component


To add the navigation component, we’ll just generate it!
There are two ways to generate a component.
Here’s the first way to do it:

1 ng generate component navigation

Alternatively, we can run a shorthand version of the above command:

1 ng g c navigation

Obviously, the g is short for generate, and the c is short for component.
This is the output of the above command in the console:

The output of the ng generate command

Here is the updated file structure of the ./src/app folder after Angular CLI generates our navigation
component:
Chapter 2: Generating components 24

The newly generated navigation component

If you open the navigation folder, you’ll see the following files:

• navigation.component.css (i.e the CSS)


• navigation.component.html (i.e the TPL - the Template)
• navigation.component.spec.ts (i.e the test file)
• navigation.component.ts (i.e the Class)

Note that our navigation component’s structure is exactly the same as what we had in the
AppComponent. The only difference is that the AppComponent had two additional files: the
app.module.ts and app-routing.module.ts. This makes perfect sense, because Angular modules
are used to combine several components together, which is what we will do next.
If we were to describe our new navigation component’s files in a diagram, it would look almost the
same as the diagram for the AppComponent, minus the two module files:
Chapter 2: Generating components 25

A diagram of the newly generated navigation component

Notice that in the above diagram, we are ignoring the testing file (app.component.spec.ts), just like
we did in the diagram of the App Component earlier in this book, in chapter 1.
Chapter 2: Generating components 26

The contents of the class file in the navigation component

Looking at the contents of the Class file of our navigation component, we can see that at the very
top, there is an import of Component and OnInit from the framework’s core.
Both the Component and the OnInit are examples of an interface.
In TypeScript (and some other languages), an interface is used when we want to make sure that a
class sticks to a contract of sorts. What this means is that a class will implement an interface. So
if we define an interface to have the property of name set to string, that means that a class which
will implement that interface will have to have a property name set to a string. So when we say that
an interface is sort of like a contract, what we mean is that if something is defined in the interface,
than that same thing should be used in a class implementing the interface.
On lines 3-7 of our code, the @Component decorator defines the selector, the templateUrl, and the
styleUrls - just like we saw in the App Component’s class.

Next, we export the NavigationComponent class. It implements the OnInit interface. The OnInit
interface is a part of the component lifecycle mechanism. A component, during its life, gets
initialized, added to the virtual DOM, etc. The ngOnInit() allows us to tap into this lifecycle and do
Chapter 2: Generating components 27

something at a certain point of a component’s life: in our case, when the component gets initialized.
Of course, the ngOnInit() is just one method inside the lifecycle sequence. There are others too.
Here’s the full list of lifecycle hooks:

• ngOnChanges()
• ngOnInit()
• ngDoCheck()
• ngAfterContentInit()
• ngAfterContentChecked()
• ngAfterViewInit()
• ngAfterViewChecked()
• ngOnDestroy()

Back to our NavigationComponent, on line 10 of its class file, we can see the call to a constructor:

1 constructor() {}

We inject dependencies of our class inside this constructor() method. On the other hand, the
ngOnInit is ran after the component’s DOM is built and injected, and all the dependencies that
came into the constructor are processed.
The constructor simply constructs our component.
Once a component is “alive”, we can use various lifecycle hooks. Since we want to add some logic
as soon as the component is mounted into the DOM, we tap into the ngOnInit moment of our
component’s lifecycle.
Of course, this was all generated for us, so at this moment we are not adding any updates to the
ngOnInit lifecycle hook.
So, there it is, we’ve just covered the code inside the class file for our newly generated
NavigationComponent.
Next, we’ll look at the template file and the CSS file of our NavigationComponent.
The Template file for our NavigationComponent is really simple, just a <p> tag with the text
“navigation works!” inside of it.
The CSS file for the NavigationComponent is currently empty.
Thus far, this is all the code for our navigation component.
Let’s now improve it, by first adding the actual navigation code to the Template file of our
NavigationComponent.

2.1.1 Updating the Template File (the HTML) of our


NavigationComponent

This is the code that we’ll add to our navigation.component.html file:


Chapter 2: Generating components 28

1 <nav>
2 <li><a href="#">One</a></li>
3 <li><a href="#">Two</a></li>
4 <li><a href="#">Three</a></li>
5 </nav>

Ok, so that’s easy enough. Next, we need to actually display this code on our webpage.

2.1.2 Displaying the NavigationComponent on Our Web Page


Let’s think this through:

1. When we open our localhost:4200, a web page displays the text “Welcome to my-app!”.
2. We know that these words come from app.component.html file.

So how to we “tell” the app component to show the navigation component?

2.1.3 “Telling” the app component to show the navigation


component
To add the navigation component to the app component, we will need to update the
app.component.html file, like this:

1 <app-navigation></app-navigation>
2
3 <div>
4 <h1>
5 Welcome to {{ title }}!
6 </h1>
7 </div>
8
9 <router-outlet></router-outlet>

Now we can save and refresh, and this is what we’ll see in the browser:
Chapter 2: Generating components 29

Added navigation component to the app component

Now we can refer back to the schematic display of our Angular app, and see how these two
components fit together right now:
Chapter 2: Generating components 30

A diagram of how the navigation component and the app component fit together

We can conclude from the image above that the NavigationComponent is simply a child of the
AppComponent. However, there is more to it than just adding the <app-navigation> custom tag to
the AppComponent template file, and it has to do with Angular automatically updating files when a
component gets created.

2.1.4 When We Generate A Component, Angular Automatically


Updates app.module.ts.
As we can see in the above title, the NavigationComponent is automatically added to our
app.module.ts file. Let’s look at app.module.ts after the navigation component was generated:
Chapter 2: Generating components 31

1 import { BrowserModule } from '@angular/platform-browser';


2 import { NgModule } from '@angular/core';
3
4 import { AppRoutingModule } from './app-routing.module';
5 import { AppComponent } from './app.component';
6 import { NavigationComponent } from './navigation/navigation.component';
7
8 @NgModule({
9 declarations: [
10 AppComponent,
11 NavigationComponent
12 ],
13 imports: [
14 BrowserModule,
15 AppRoutingModule
16 ],
17 providers: [],
18 bootstrap: [AppComponent]
19 })
20 export class AppModule { }

As discussed earlier, there were four import statements initally. Now there are five. The fifth import
statement reads:

1 import { NavigationComponent } from './navigation/navigation.component';

Of course, as it was mentioned earlier when we were looking at how @NgModule works, we need
to declare all the components that the app module will use. Initially, when we generated our
app, the declarations only had a single file, the AppComponent. Now, it’s updated to include the
NavigationComponent too:

1 declarations: [
2 AppComponent,
3 NavigationComponent
4 ]

This is our updated file with code updates highlighted by Git:


Chapter 2: Generating components 32

A screenshot of our app module file’s changes highlighted by Git after running the ng generate command to generate
the navigation component

This is all that it takes for a new component to be added to a module in Angular. Even better, Angular
does this automatically whenever a new component is generated. Now that we know how this works,
we will have no problems to add other components and understand what behavior to expect and
how everything fits together.

2.1.5 Styling the Navigation Component


Obviously, our navigation is currently unstyled, so we can update the navigation.component.css
file with some simple styling to make it look more like an actual navigation.
So let’s update the said file with this code:
Chapter 2: Generating components 33

1 /* navigation.component.css */
2 nav {
3 height: 100vh;
4 float: left;
5 width: 150px;
6 background: tomato;
7 list-style-type: none;
8 }
9
10 nav li {
11 font-family: Arial;
12 font-size: 16px;
13 padding: 12px 20px 5px;
14 border-bottom: 1px solid white;
15 }
16
17 nav li a {
18 color: white;
19 text-decoration: none;
20 }

Here’s a screenshot of the above code from the editor.


Chapter 2: Generating components 34

A screenshot of our app module file’s changes highlighted by Git after running the ng generate command to generate
the navigation component

Ok, so the design is nothing to write home about, but at least we now have a sidebar navigation.
Chapter 2: Generating components 35

A simple sidebar nav after our styling update

2.2 Updating the CSS of the app component


To give some spacing between the app component and the navigation sidebar, we need to update
both the app.component.html and the app.component.css files:

1 <!-- app.component.html -->


2 <app-navigation></app-navigation>
3
4 <div class="p20">
5 <h1>
6 Welcome to {{ title }}!
7 </h1>
8 </div>
9
10 <router-outlet></router-outlet>

Now let’s update the app.component.css file:


Chapter 2: Generating components 36

1 .p20 {
2 padding: 20px;
3 }

Let’s now inspect our app in the browser:

Our styles are not working as we expected

The reason for this is the fact that we need to update the styles of the DOM-generated app-root
component.
There are several ways to do it, but an interesting (and easy) approach is to use the :host selector
inside the app.component.css file.

2.3 Using the :host selector in the app.component.css file


This is the update to our app.components.css file:
Chapter 2: Generating components 37

1 :host {
2 display: flex;
3 }
4 .p20 {
5 padding: 20px;
6 }

Now our app will look a lot nicer.


Here’s a screenshot of hovering over the DOM elements to see the flexbox higlights in the Chrome
browser.

A screenshot of the result of using the :host selector in app component’s css

Next, we’ll add another component, and we’ll call it ProfileComponent. This time, however, we
won’t generate it, but rather write it from scratch.
Chapter 2: Generating components 38

Note: If you’re curious to see the changes made in the second chapter in our Git repo,
navigate to the commit message titled https://github.com/ImsirovicAjdin/angular-book-
1/commit/30c000ad5e652c8251964683dfe09dcd1d957466⁶.
⁶2.Generatethenavigationcomponentandupdatestyles
Chapter 3: Writing an Angular
component from scratch
In this chapter, we will:

• 3.1 write the ProfileComponent from scratch


• 3.2 add global styles

3.1 Writing the ProfileComponent from scratch


Remember the NavigationComponent diagram? We can use it to remind ourselves of the building
blocks that our component must have.
Actually, let’s simplify this even further, and instead of looking at an image, let’s use some ASCII
art and make a diagram for any component we might wanna add:

1 ____________________________________
2 | | | | |
3 | Any Component: | C | T | S |
4 |________________|_____|_____|_____|

Looking at the above “diagram”, we can say that any Angular component must have at least three
files:

• C (the Class file, *.ts)


• T (the Template file. *.html)
• S (the Style file, *.css)

Let’s now make our ProfileComponent.


First, we’ll open app.module.ts, and import our component.
Note that as you go through the steps below, Angular CLI will throw some warnings and errors. Just
ignore them - it’s all going to work out.
Inside the app.module.ts, under the NavigationComponent import, let’s add:
Chapter 3: Writing an Angular component from scratch 40

1 import { ProfileComponent } from './profile/profile.component';

Next, still inside the app.module.ts file, let’s add the newly imported component to declarations
inside @NgModule decorator:

1 @NgModule({
2 declarations: [
3 AppComponent,
4 NavigationComponent,
5 ProfileComponent
6 ],

Now we’re done with the app.module.ts file, and we can go on by adding a new folder inside
./src/app. We’ll call it profile. Inside the profile folder there will be three new files:

• C, profile.component.ts
• T, profile.component.html
• S, profile.component.css

Here is the contents of the profile.component.ts file:

1 // ./src/app/profile/profile.component.ts
2 import { Component, OnInit } from '@angular/core';
3
4 @Component({
5 selector: 'app-profile',
6 templateUrl: './profile.component.html',
7 styleUrls: ['./profile.component.css']
8 })
9 export class ProfileComponent implements OnInit {
10
11 constructor() { }
12
13 ngOnInit() {
14 }
15
16 }

Before we continue, we can see that this component’s class is almost identical to the
navigation.component.ts class.

This leads us to an interesting conclusion: let’s say that we could replace any component’s name
with this string: <component-name>. In that case, we could say that any component, when it gets
generated, has the following structure:
Chapter 3: Writing an Angular component from scratch 41

1 import { Component, OnInit } from '@angular/core';


2
3 @Component({
4 selector: 'app-<component-name>',
5 templateUrl: './<component-name>.component.html',
6 styleUrls: ['./<component-name>.component.css']
7 })
8 export class <Component-name>Component implements OnInit {
9
10 constructor() { }
11
12 ngOnInit() {
13 }
14
15 }

Next up, we’ll add the template file (the “T” in our diagram) for the ProfileComponent:

1 <!-- ./src/app/profile/profile.component.html -->


2 <div class="p20">
3 <h1>
4 Profile works!
5 </h1>
6 </div>

Finally, the styles file (the “S” in our diagram), as we’ve already come to expect, is initially just an
empty file called profile.component.css. However, in order for our profile component not to be
glued to the sidebar, we need to add it the same styles that we added to the app component. So let’s
just copy the styles from app.component.css and paste them into profile.component.css:

1 .p20 {
2 padding: 20px;
3 }

At this point, your app should refresh, and be working. If it is not, you might have to stop the
ng serve command by pressing the CTRL c keyboard shortcut. After stopping the Angular server,
simply restart it. Your app should be served fine.
Our app at this point is saved in the commit message titled: 3.1. Add the profile component without
using the ng generate component command⁷
⁷https://github.com/ImsirovicAjdin/angular-book-1/commit/5c7efba1d6967ea8de5108baa9c0b4e17859ef94
Chapter 3: Writing an Angular component from scratch 42

3.2 Adding global styles


We now have exact same CSS code inside two different components of ours. Sometimes that
is completely fine. Other times, it’s better to provide shared CSS code to our entire app. To do
that, we can use the styles.css file, that’s located in the root of the ./src folder. So let’s open
./src/styles.css, and paste in the .p20 class:

1 /* ./src/styles.css */
2 .p20 {
3 padding: 20px;
4 }

Now we can delete the .p20 class from both the app.component.css and the profile.component.css
files.
This updated commit is saved under git commit titled: 3.2 Add a global style and clean up the
component styles⁸
Next, we’ll add a new view to our router, and that new view will show our profile page.
⁸https://github.com/ImsirovicAjdin/angular-book-1/commit/6e0d14ddcf0017c704d5ad2f1fae39d58be3ffe9
Chapter 4: Using Routing and Adding
a Login Component
In this chapter, we’ll show the profile page using Angular routing.
Specifically:

• we’ll list different routes


• we’ll add routing logic using app-routing.module.ts

Additionally, we’ll add a login component.

4.1 Showing the Profile Page


Let’s go back to the app.component.html file, and make sure that we have the <router-outlet> tag
present. The file should look like this:

1 <!-- app.component.html -->


2 <app-navigation></app-navigation>
3
4 <div class="p20">
5 <h1>
6 Welcome to {{ title }}!
7 </h1>
8 </div>
9
10 <router-outlet></router-outlet>

Next, we’ll need to go to the navigation component’s template, i.e the navigation.component.HTML
file, and change the contents so that it looks like this:

1 <nav>
2 <li><a routerLink="/">Home</a></li>
3 <li><a routerLink="/profile">Profile</a></li>
4 </nav>
Chapter 4: Using Routing and Adding a Login Component 44

What have we just done here? We have used a custom Angular attribute, routerLink, and we have
set the root route to Home, and the /profile route to Profile.
Let’s inspect our updated site in the browser.

The navigation using routerLink attribute on anchor tags

However, this is just an HTML template. There is no logic behind these routes. In other words,
although the links are showing in the website’s navigation, we have not specified how these routes
should work whatsoever.
The Angular way of specifying routes is to add them to the app-routing module, which we’ll do
next.

4.2 Adding Routes to app-routing.module.ts


Inside the app-routing.module.ts file, we need to specify each route as an object. All of these objects
are added to the Routes array, like this:

1 const routes: Routes = [


2 {...},
3 {...}
4 ]

We need the profile route, so we’ll add it as a separate object:


Chapter 4: Using Routing and Adding a Login Component 45

1 {
2 path: 'profile',
3 component: ProfileComponent
4 },

The path property sets the actual URL address that will be appended to the base URL of our app.
So, if the base URL of our app is localhost:4200, then the ProfileComponent will be served on this
path: localhost:4200. In other words, this will be our root route.
Likewise, if the base URL of our app is localhost:4200, the ProfileComponent will be served on this
path: localhost:4200/profile.
Before we can save our updated app-routing.module.ts file, we need to make sure that the
components we’re referencing inside the Routes array are imported. Thus, the fully updated
app-routing.module.ts file will look like this:

1 import { NgModule } from '@angular/core';


2 import { RouterModule, Routes } from '@angular/router';
3 import { ProfileComponent } from './profile/profile.component';
4
5 const routes: Routes = [
6 {
7 path: 'profile',
8 component: ProfileComponent
9 }
10 ];
11
12 @NgModule({
13 imports: [RouterModule.forRoot(routes)],
14 exports: [RouterModule]
15 })
16 export class AppRoutingModule { }

Great, now our routing works!


The app at this point is saved as commit with the following message: 4. Add the routing using router
module and routerLink⁹.
However, we do have a slight wrinkle to iron out: when we click the Home link in the navbar, our
site, expectedly, looks like this:
⁹https://github.com/ImsirovicAjdin/angular-book-1/commit/aca5a08d797bacceddc69cd3e86bf30e3c1c1ea0
Chapter 4: Using Routing and Adding a Login Component 46

The screen after clicking the Home link in the navigation

However, when we click the Profile link in the navbar, we get the following:

The screen after clicking the Profile link in the navigation

What does this mean, and how do we fix it?


It means that we need to update the code in the app.component.html file, from this:
Chapter 4: Using Routing and Adding a Login Component 47

1 <!-- app.component.html -->


2 <app-navigation></app-navigation>
3
4 <div class="p20">
5 <h1>
6 Welcome to {{ title }}!
7 </h1>
8 </div>
9
10 <router-outlet></router-outlet>

… to this:

1 <!-- app.component.html -->


2 <app-navigation></app-navigation>
3
4 <router-outlet></router-outlet>

However, if we just left it like this, it means that our site visitors would not see the greeting Welcome
to {{ title }}!, ever.

Before we fix this “problem”, let’s step back outside the Angular world, and think about it logically.
What’s the one thing that we always need to have on a website, regardless of what page we’re on?
Well, beside the obvious navigation, the answer might be: a logo, or a footer.
Let’s go with the logo.
We’ll just change the HTML from this:

1 <div class="p20">
2 <h1>
3 Welcome to {{ title }}!
4 </h1>
5 </div>

…to this:

1 <div>
2 <h1><a routerLink="/">{{ title }}</a></h1>
3 </div>

Let’s also update our styles so that our app looks nicer.
We’ll update several files:
Chapter 4: Using Routing and Adding a Login Component 48

1. In src/app/app.component.html, we’ll update the h1, and give it an anchor using routerLink
2. In src/app/app.component.css, we’ll update the :host styles
3. In src/app/navigation/navigation.component.css, we'll update the nav and nav li‘
selectors

Here’s the updated app.component.html:

1 <!-- app.component.html -->


2 <app-navigation></app-navigation>
3
4 <div>
5 <h1><a routerLink="/">{{ title }}</a></h1>
6 </div>
7
8 <router-outlet></router-outlet>

Here’s the updated app.component.css:

1 :host {
2 display: flex;
3 flex-wrap: wrap;
4 flex-direction: column;
5 }

And here’s the updated navigation.component.css:

1 /* navigation.component.css */
2 nav {
3 height: 37px;
4 width: 100%;
5 display: block;
6 background: tomato;
7 list-style-type: none;
8 }
9
10 nav li {
11 font-family: Arial;
12 font-size: 16px;
13 padding: 12px 20px 5px;
14 border-right: 1px solid white;
15 display: inline-block;
16 }
Chapter 4: Using Routing and Adding a Login Component 49

17
18 nav li a {
19 color: white;
20 text-decoration: none;
21 }

Viewing our site in the browser, after the above changes, we get this:

Our Angular app after updating the styles

This slight detour in the development of our app was taken so as to highlight a couple of points:

1. We need a more robust way of dealing with the styles (which we’ll mark as an item on our
app’s “todo list”, and deal with it later in the book)
2. We needed a reminder of how to add some code that will show up in all pages of our app.

While the first point is something to take care of later, the second point leads to an interesting
conclusion:
To repeat a piece of code in our App module, we can either add it right inside the App component’s
template file, or we can import it as a separate component.
It might be an obvious conclusion, but it’s worth repeating as it’s one of the cornerstones of how we
build apps in Angular.
We’ve made enough incremental updates to our app to warrant another Git commit, so let’s name
this one as follows: 4.1 Turn the sidebar nav into a horizontal nav¹⁰.
Let’s move on now, and practice adding another component to our App module.

4.3 Adding a login component


Now might be a good time to add another component to our app, so that we can have an additional
route, just for the sake of practice.
¹⁰https://github.com/ImsirovicAjdin/angular-book-1/commit/435c43ecbf004ebe089b8865176a15de542c95ca
Chapter 4: Using Routing and Adding a Login Component 50

We’ll call this new component: LoginComponent.


Let’s list out all the steps we need to take:

1. Add a new folder inside ./src/app/, and call it login


2. Add the C, T, and S files
3. Import the LoginComponent to app.module.ts, and add it to the declarations array inside app
module’s @NgModule decorator
4. Import the LoginComponent to app-routing.module.ts and add it to the Routes array.
5. Update the navigation.component.html file with the new routerLink for the Login path.

We’ll begin with steps number 1 and 2 from the above list. We’ll add the ./src/app/login com-
ponent, and we’ll add the login.component.ts, login.component.html, and login.component.css
files.
Here is the code for the class file:

1 // login.component.ts
2
3 import { Component, OnInit } from '@angular/core';
4
5 @Component({
6 selector: 'app-login',
7 templateUrl: './login.component.html',
8 styleUrls: ['login.component.css']
9 })
10 export class LoginComponent implements OnInit {
11
12 constructor() { }
13
14 ngOnInit(): void {
15 }
16
17 }

This is the code for the template file:


Chapter 4: Using Routing and Adding a Login Component 51

1 <!-- login.component.html -->


2
3 <div class="p20">
4 <h1>
5 Login works!
6 </h1>
7 </div>

The style file (login.component.css) will remain empty, but we’ll still add it in case we might need
to add some styles later.
Next up, after we’ve imported the LoginComponent to app.module.ts, we’ll add it to the list of
declarations inside the @NgModule decorator.

1 // ...code abbreviated for clarity...


2
3 import { LoginComponent } from './login/login.component';
4
5 @NgModule({
6 declarations: [
7 AppComponent,
8 NavigationComponent,
9 ProfileComponent,
10 LoginComponent
11 ],
12
13 // ...code abbreviated for clarity...

Next, we’ll import the LoginComponent so that we can update the Routes array inside the
app-routing.module.ts, with this new path:

1 // ...code abbreviated for clarity...


2 {
3 path: 'login',
4 component: LoginComponent
5 }
6 // ...code abbreviated for clarity...

Here’s the full updated code of app-routing.module.ts:


Chapter 4: Using Routing and Adding a Login Component 52

1 import { NgModule } from '@angular/core';


2 import { RouterModule, Routes } from '@angular/router';
3 import { LoginComponent } from './login/login.component';
4 import { ProfileComponent } from './profile/profile.component';
5
6 const routes: Routes = [
7 {
8 path: 'profile',
9 component: ProfileComponent
10 },
11 {
12 path: 'login',
13 component: LoginComponent
14 }
15 ];
16
17 @NgModule({
18 imports: [RouterModule.forRoot(routes)],
19 exports: [RouterModule]
20 })
21 export class AppRoutingModule { }

Finally, we’ll add a new routerLink inside navigation.component.html, pointing to the /login path:

1 <nav>
2 <li><a routerLink="/">Home</a></li>
3 <li><a routerLink="/profile">Profile</a></li>
4 <li><a routerLink="/login">Login</a></li>
5 </nav>

Now’s the time for another git commit.


This one, we’ll name 4.2 Add the login component¹¹.
Let’s review the updated app in the browser:
¹¹https://github.com/ImsirovicAjdin/angular-book-1/commit/8ffbe56dd52c904494cdd3fbe77bf33967cc95bf
Chapter 4: Using Routing and Adding a Login Component 53

Our Angular app after adding the login component

In the next chapter, we’ll look at how to bind HTML in our templates to events.
Chapter 5: Binding
5.1 Binding Template Files to Class Files
There are many ways to connect template files with class files in Angular components. Any kind of
binding between these two files is what’s known as data binding.
There are 3 kinds of data binding in Angular:

• Interpolation (we’ve already seen that; it’s simple variable interpolation using the mustache
syntax)
• Event binding (handling events): an example is a (click) event binding; all event bindings are
surrounded with a pair of parentheses, i.e ()
• Property binding: we bind any HTML element’s property using the square brackets, i.e []

5.2 Binding events in Angular


First of all, it’s important to know that there are two kinds of events we can use in Angular.

• Regular JavaScript events (aka “DOM Events”), such as (click)


• Angular events (they begin with ng), such as (ngSubmit)
• We’ll begin by binding a click event to our AppComponent template file.

5.3 Binding a (click) event to AppComponent template file


We’ll be updating two files:

• app.component.html (i.e the Template)


• app.component.ts (i.e the Class)

We’ll be adding a button with a (click) event. The updated template file will look like this:
Chapter 5: Binding 55

1 <!-- app.component.html -->


2 <app-navigation></app-navigation>
3
4 <div>
5 <h1><a routerLink="/">{{ title }}</a></h1>
6 </div>
7 <button (click)="randomColor()">
8 Give me a random color!
9 </button>
10
11 <router-outlet></router-outlet>

As we can see above, a (click) event will run a randomColor function. We’ll define it next.

5.4 Defining the randomColor function inside


app.component.ts

We’ll add our randomColor function definition inside the app.component.ts file. This is the code:

1 // ... code skipped for brevity


2
3 export class AppComponent {
4 title = 'my-app';
5
6 randomColor() {
7 let hex = '#'+Math.random().toString(16).substr(-6);
8 alert(`This is a random color: ${hex}`);
9 }
10 }

Our updated app now looks like this:


Chapter 5: Binding 56

Our Angular app after adding the random color button

Let’s now try clicking the button inside the AppComponent (on the root route). We’ll get an alert with
a custom HEX color.
What we just did here? We’ve setup a click event handler inside a component’s template file. This
handler is simply a call to a function, which we’ve defined in the component’s class file.
What this means is that all the component’s logic lives inside a component’s class file.
Now’s a good time for a git commit. Let’s name this commit 5. Bind events in the component template
file to the logic in the component class file¹².

5.5 Property binding in Angular


We use square brackets to bind to HTML element properties in Angular.
Here is a simple example of the syntax:

1 <table [border]>...</table>

Above, using square brackets, we’ve bound the border html attribute on the table tag inside the
template file of a component, to its class file.
Let’s say that again.
We’ve bound:

• the border html attribute (the one on the tabletag inside the template file of our component)

To:

• the component’s class file

Now we can set the border inside the class file, like this:
¹²https://github.com/ImsirovicAjdin/angular-book-1/commit/2b6ad3a194210e8fdcd18fade96255a2be12cd85
Chapter 5: Binding 57

1 export class AppComponent {


2 ...
3 border = "10";
4 ...
5 }

We’ve just set our table’s border to the width of 10 pixels. Let’s now write the actual code and really
add this to our app.component.html. This is the updated file:

1 <app-navigation></app-navigation>
2
3 <div>
4 <h1>
5 <a routerLink="/">{{ title }}</a>
6 </h1>
7 <button (click)="randomColor()">Give me a random color!</button>
8
9 <table [border]="this.border">
10 <tr>
11 <th>Year</th>
12 </tr>
13 <tr>
14 <td>2021</td>
15 </tr>
16 <tr>
17 <td>2020</td>
18 </tr>
19 </table>
20 </div>
21
22 <router-outlet></router-outlet>

And here is the updated app.component.ts file:


Chapter 5: Binding 58

1 import { Component } from '@angular/core';


2
3 @Component({
4 selector: 'app-root',
5 templateUrl: './app.component.html',
6 styleUrls: ['./app.component.css']
7 })
8 export class AppComponent {
9 title = 'myapp';
10 border = 10;
11
12 customColor() {
13 let hex = '#'+Math.random().toString(16).substr(-6);
14
15 alert( `This is a custom color: ${hex}` );
16 }
17 }

Let’s save these changes in Git, with this commit message: 5.1 Bind an HTML attribute in the
component template file to a property in the component class file¹³.
Let’s also review the updates in the browser.
¹³https://github.com/ImsirovicAjdin/angular-book-1/commit/01a8520d3fe05455fbc98b535cefd9a6b731c7fb
Chapter 5: Binding 59

Our Angular app after adding the table and binding its border to a property in the component’s class file

5.5.1 Dynamically update HTML attributes using


property binding and method calls
Now we can update it further so the border width is truly dynamic.
First we’ll look at a piece of code that won’t work. Here’s the code:

1 export class AppComponent {


2 title = 'myapp';
3 border = randomWidth();
4
5 customColor() {
6 let hex = '#'+Math.random().toString(16).substr(-6);
7
8 alert( `This is a custom color: ${hex}` );
9 }
10
11 randomWidth() {
12 return Math.round(Math.random()*100);
13 }
14 }
Chapter 5: Binding 60

If you ran the above code, you’d get the following error:

1 ERROR in src/app/app.component.ts(10,12): error TS2663: Cannot find name 'randomWidt\


2 h'. Did you mean the instance member 'this.randomWidth'?

Here’s the error in the console:

Did you mean the instance member ‘this.randomWidth’? - in the console

The error also shows up in the browser:

Did you mean the instance member ‘this.randomWidth’? - in the browser

Additionally, the error appears in the VS Code editor as well:


Chapter 5: Binding 61

Did you mean the instance member ‘this.randomWidth’? - in VS Code

Regardless of how we “catch” this error, we need to fix it.


And to answer the error’s question, indeed, we meant this.randomWidth. So let’s update our code
to this:

1 import { Component } from '@angular/core';


2
3 @Component({
4 selector: 'app-root',
5 templateUrl: './app.component.html',
6 styleUrls: ['./app.component.css']
7 })
8 export class AppComponent {
9 title = 'my-app';
10 border = this.randomWidth();
11
12 constructor() {
13 console.log(this.randomWidth());
14 }
15
16 randomColor() {
17 let hex = '#'+Math.random().toString(16).substr(-6);
18 alert(`This is a random color: ${hex}`);
19 }
20
21 randomWidth() {
22 return Math.round(Math.random()*100);
23 }
24 }
Chapter 5: Binding 62

Now our error is gone, and the easiest way to verify it using VS Code:

No errors in VS Code

Now our app works again, and every time we refresh our app on the root route, we get a border
with a dynamically set width. This time we’ve also logged out the function definition to the console,
using the constructor method.

Logging the value of table border width to the console using the constructor method

These updates are ripe for another git commit: 5.2 Dynamically update html attributes using property
Chapter 5: Binding 63

binding and method calls¹⁴.

5.6 Binding a property to a button click


In this exercise, we’ll bind our border property to a button click.
As we know, the border property inside the App Component’s template, is set to
this.randomWidth(). Additionally, a button click event calls the customColor() property of
the AppComponent’s class.
We’ll now combine the two.
We have a slight wrinkle here, since we’re trying to return two values from a JS function.
You might think about approaching a solution to this issue as follows:

• JS functions only return 1 value.


• Thus, we’ll have to make that one value an array, and then we’ll specify the two array members.

This approach will not work, but let’s look at how we might write this in code. Note the question
marks (i.e “????”) in places where we simply do not have an easy way to actually assign values we
need without the compiler throwing errors:

1 // ... code skipped for brevity ...


2 export class AppComponent {
3 title = 'my-app';
4 border = ???? ;
5 color = ???? ;
6
7 constructor(){
8 console.log(this.randomWidthAndCustomColor);
9 }
10
11 randomWidthAndCustomColor() {
12 let random = Math.round(Math.random()*100);
13 let hex = '#'+Math.random().toString(16).substr(-6);
14
15 let arr = [random, hex];
16
17 return random;
18 }
19 }

Since the above approach will not work, let’s look at an actual solution:
¹⁴https://github.com/ImsirovicAjdin/angular-book-1/commit/eea75adaafc9c8a32914f1faa6cfc2be1fe0c9f7
Chapter 5: Binding 64

1 // ... code skipped for brevity ...


2 export class AppComponent {
3 title = 'myapp';
4 border = 0;
5 color = '';
6
7 constructor(){
8 console.log(this.randomWidthAndCustomColor);
9 }
10
11 randomWidthAndCustomColor() {
12 this.border = Math.round(Math.random()*100);
13 this.color = '#'+Math.random().toString(16).substr(-6);
14 }
15 }

Looking at the above code, we can see that it’s actually very elegant. Inside the class, we first have
our variables: title, border, and color.
We can skip the constructor (since we already explained that it’s just an easy way to console.log
values from a class member).
The interesting bit, and the solution to our little wrinkle, is in the updated code of the
randomWidthAndCustomColor(), where we assign the Math.random() calculations to this.border
and this.color, respectively.
Now we can update the app component’s template file, like this:

1 <!-- ... code skipped for brevity ... -->


2 <button (click)="randomWidthAndCustomColor()" [style]>Click me!</button>
3
4 <table [border]="this.border" [bgColor]="this.color">
5 <tr>
6 <th>Year</th>
7 </tr>
8 <tr>
9 <td>2021</td>
10 </tr>
11 <tr>
12 <td>2020</td>
13 </tr>
14 </table>
15 <!-- ... code skipped for brevity ... -->

Now we have a working app again.


Chapter 5: Binding 65

This time, every time we refresh it, it will show a different table background and a different width
on the table border.
The Git commit for this improvement will also hold the previous code, commented out - that way
we’ll be able to more easily compare the updates, in a single commit, rather than comparing them
across two or more commits.
Note that committing commented code is not a good practice, and we won’t keep doing it in this
book. This is more of a one-of exception.
This Git commit message reads: 5.3 Binding properties to button click events¹⁵.
Next, we’ll discuss one-way versus two-way data binding.

5.7 Comparing one-way and two-way data binding in


Angular
So far, we’ve seen examples of one-way binding:

• variable interpolation with the mustache syntax, {{}}


• property binding with square brackets, []
• event binding with round brackets, ()

In the first two cases (variable interpolation and property binding), the data goes in one-way, from
the data source (in our example, the class file), to our view template.
In the case of event binding, the data flows from the view to the class (i.e to the data source).
Two-way binding is simply a combination of these two data flows: the data can flow from the view
to the class, and it can also flow from the class to the view.
This is the syntax of two-way binding in angular:

1 [(target)]="expression"

This syntax of square brackets surrounding round brackets - the [()] syntax - is known as the
‘banana in a box’ syntax.
This two-way binding syntax is simply a combination of both versions of one-way data binding, so
we could rewrite banana in a box to this:

1 <element [target]="something" (target)="anotherThing">

Next, we’ll discuss property bindings (with []) in more detail.


¹⁵https://github.com/ImsirovicAjdin/angular-book-1/commit/11d76dcb0c0a692926fd86e0adde5fba3c6109aa
Chapter 5: Binding 66

5.8 Examining Property Bindings in Angular in More


Detail
Based on what we’ve covered so far, you might think that property binding in Angular is limited to
regular HTML attributes. However, it goes much further than that. Consider the following examples:

1 <p [innerText]=""></p>
2
3 <p [style.color]="styleColor">
4 Lorem ipsum dolor sit amet
5 </p>

The official Angular documentation refers to Angular’s HTML templates as “HTML plus”, meaning
it’s more than just plain old HTML. It also mentions that instead of looking at property bindings as
simply a way to interact with HTML attributes, it is rather a way to interact with DOM properties.
It even lists the differences between regular HTML attributes and DOM properties, which is an
important and insightfull read.
So, to aid in our understanding of the property binding syntax, we’ve made an intentional error
earlier in the text, and now’s the time to fix it: property binding in Angular does not work on
HTML attributes, but rather on DOM properties!
To quote the official docs: “The HTML attribute and the DOM property are not the same thing, even
when they have the same name.”
Let’s now extend our Angular app with some additional property binding.
Open the app.component.html file and update the <table> element to this:

1 <table [border]="this.border" [bgColor]="this.color">


2 <tr>
3 <th [innerText]="this.yearTitle">Year</th>
4 </tr>
5 <tr>
6 <td>2019</td>
7 </tr>
8 <tr>
9 <td>2018</td>
10 </tr>
11 </table>

We’ve updated the first <th> element to [innerText]="this.yearTitle", so now we need to specify
the value for yearTitle in our component’s class file, namely in app.component.ts:
Chapter 5: Binding 67

1 // ... code skipped for brevity ...


2 export class AppComponent {
3 yearTitle = 'The year';
4 title = 'myapp';
5 border = 0;
6 color = '';
7 // ... code skipped for brevity ...

We’ve just dynamically set the innerHTML property on an HTML element using property binding
in Angular! This update now adds the text “The year” to the first cell of the HTML table under
the “Click me!” button. Note how the innerText property binding overrides the static “Year” text
between the p opening and closing tags.
We’ll save this in another git commit message: 5.4 Binding innerHTML property¹⁶.
Next, we’ll add some services to our app, so that we can work with data.
¹⁶https://github.com/ImsirovicAjdin/angular-book-1/commit/06906fd03e7c29eb44721d0be462253637924f59
Chapter 6: Services
Services in Angular are used as data providers.
For example, an Angular service can get some data from the server, and inject it into a component.
A service has some methods defined to call a server and get data.
We can then call these methods from our components’ classes, and then pass this data on to our
components’ template files.
Thanks to the two-way data binding, we can easily update the data model from our template files
too.
Let’s add a service to our example app, so that we see how it works.

6.1 Adding a service to our app


We’ll run the following code in our console:

1 ng generate service somedata

Similar to what we’ve seen for generating components, we can use shorthand syntax here as well,
which would simply be:

1 ng g s somedata

Once we run this command, our app will be updated with the following:

1. An ./src/app/somedata.service.ts file will be added


2. An ./src/app/somedata.service.spec.ts file will be added

Let’s commit this generated code: 6. Run ng g s somedata to generate the SomedataService¹⁷.

6.1.1 Inspect the generated service files


We can ignore the *.spec.ts file as it is intended for testing our application, and we won’t cover
that just yet.
Let’s inspect the contents of somedata.service.ts file:
¹⁷https://github.com/ImsirovicAjdin/angular-book-1/commit/8d8ad574cd44afd12fe67e736774ce4853c8b958
Chapter 6: Services 69

1 import { Injectable } from '@angular/core';


2
3 @Injectable({
4 providedIn: 'root'
5 })
6 export class SomedataService {
7
8 constructor() { }
9 }

Similar to @Component and @NgModule, the @Injectable is a decorator. This decorator only shows
the providedIn property inside its object literal. It also exports the SomedataService class, with an
empty constructor function.
As we can see, the service is as barebones as it can get.

6.1.2 Removing redundant comments


Before we continue, let’s also clean up our app by removing redundant comments from an earlier
commit. While it’s sometimes good to comment the code we write, it’s usually good if we remove
the code we won’t use again.
In app.component.ts, we’ll remove all the unnecessary comments so that the complete file now
looks like this:

1 import { Component } from '@angular/core';


2
3 @Component({
4 selector: 'app-root',
5 templateUrl: './app.component.html',
6 styleUrls: ['./app.component.css']
7 })
8 export class AppComponent {
9 yearTitle = 'The year';
10 title = 'my-app';
11 border = 0;
12 color = '';
13
14 constructor() {
15 console.log(this.randomWidthAndCustomColor());
16 }
17
18 randomWidthAndCustomColor() {
Chapter 6: Services 70

19 this.border = Math.round(Math.random()*100);
20 this.color = '#'+Math.random().toString(16).substr(-6);
21 }
22 }

We’ll save this update in another commit, with the message of: 6.1 Remove redundant comments¹⁸.
Now we can go back to our generated service. We’ll use a method from the service somewhere else
in our code.

6.1.3 Add a method to our service and use it elsewhere in our


Angular app
Let’s add a method to our service so that we can then use it elsewhere in the app.
In somedata.service.ts, right under the constructor, write this code:

1 someMethodFromService() {
2 return 42;
3 }

Now let’s go back to the App Component’s class file (app.component.ts), and import the
SomedataService class (on line 2):

1 import { SomedataService } from './somedata.service';

Now we need to access our service data. This is done by simply passing a private argument to the
constructor function inside the exported AppComponent class:

1 export class AppComponent {


2 // ... code skipped ...
3 constructor(private data: SomedataService){
4 console.log(this.randomWidthAndCustomColor);
5 }
6 // ... code skipped ...
7 }

Now that we have the data from SomedataService available, we can use it anywhere inside our
AppComponent class. For example, inside the randomWidthAndCustomColor() method, we can pass it
to the this.border value:

¹⁸https://github.com/ImsirovicAjdin/angular-book-1/commit/1a52db29c9bff10008b30191d697b48cce6b2a1b
Chapter 6: Services 71

1 randomWidthAndCustomColor() {
2 this.border = this.data.someMethodFromService();
3 this.color = '#'+Math.random().toString(16).substr(-6);
4 }

What effect will this have on our app? Of course, the this.border data now comes from the
someMethodFromService() - a function that lives inside our SomedataService class. And since this
value is set to 42, the border of the <table> element will no longer change.
However, not all is smooth sailing here. A problem that we’re facing at this point is that, instead of
getting the actual app in the browser, we get the “Failed to compile error message”.
Let’s inspect the console and see if we get more info there:

1 Property 'someMethodFromService' does not exist on type 'SomedataService'

Hm, that’s quite a weird message. After all, I’m pretty sure I’ve just added the someMethodFromSer-
vice() function to my SomedataService.
So what’s happening here?

6.1.3.1 Working with types in TypeScript

TypeScript is touted as a “superset of JS” - and it comes with types. Meaning, we need to add the
return type to our someMethodFromService() method definition for it to work correctly.
The updated code looks like this:

1 someMethodFromService(): number {
2 return 42;
3 }

The first line in the above code snippet determines that this function’s return value must be a number.
Now our app works again - everything compiles in the console successfully and the app displays in
the browser.

6.1.3.2 A side-note on error messages

It is a bit unfortunate that the specific error we were faced with was too vague. This requires some
explaining.
Of all the frontend technologies I’ve worked with, the Elm language is the only one that, for me, has
the satisfactory level and utility of error messages. It’s a pleasure to work with. The Elm language
inspired many concepts that are today widely used in the frontend world:
Chapter 6: Services 72

• uni-directional data flows (think Redux) - came from Elm


• error messages to help the development (on the frontend!) - sort of also came from Elm

Unfortunately, Angular’s error messaging is a lot worse than Elm’s.


So why not just use Elm? I’d love to, if there was demand for it.
Currently, Elm is simply not as popular. Maybe that will change in the future, and it’s definitely an
interesting and fun technology - and a pleasure to work with - but currently, the market share is
just not there to simply ignore Angular, React, or Vue.
However, Angular’s emphasis on code structure and reuse means that I don’t have to reinvent the
wheel every time I work with it, and that makes it more Elm-like - and the reason why I still like
Angular better than, say, React.
TL; DR: Every front-end technology has its own downsides. One such downside in Angular is the
sometimes poor error messaging. On the bright side, poor error messaging still seems to be the norm
in web development technology, rather than the exception. So let’s just sort of ignore the fact that
the above error made no sense whatsoever, and simply learn to live with it.

6.1.4
Services are used to communicate with some data source. In the above example, we just hard-coded
some values inside the SomedataService class itself.
However, a real-world scenario includes getting the actual data from an api. Angular comes with
its own http library, called HttpClient. We can use HttpClient to have some data provided from a
server.
In this book series, that backend will be powered by Node.js.
However, starting to introduce Node.js at this point would simply be a bit too much, so we’ll have
to wait just a bit more for the Node.js implementation and instead we’ll first see how to work with
HttpClient.

Also, let’s not forget to add another Git commit: 6.2 Fix the error: property someMethodFromService
does not exist on type SomedataService¹⁹.

6.2 Working with HttpClient


To get started with HttpClient, we just need to import it from @angular/common/http as an
HttpClientModule, and then list it inside the @NgModule decorator, in the imports array of the
app.module.ts file:

¹⁹https://github.com/ImsirovicAjdin/angular-book-1/commit/9e50c867f94865195a6875b2fefd088dedece0f2
Chapter 6: Services 73

1 // ... code skipped for brevity ...


2 import { HttpClientModule } from '@angular/common/http';
3
4 // ... code skipped for brevity ...
5 @NgModule({
6 declarations: [...],
7 imports: [
8 BrowserModule,
9 AppRoutingModule,
10 HttpClientModule
11 ],
12 // ...
13 })

Now we need to import the HttpClient to the somedata.service.ts file, and inject this dependency
inside our class’ constructor with a private property, like this:

1 import { HttpClient } from '@angular/common/http';


2 // ... code skipped for brevity ...
3
4 constructor(private http: HttpClient) { }
5
6 // ... code skipped for brevity ...

We also need to use a restful api.


We need to get some numbers from our api, so we’ll use https://api.mathjs.org/.
Specifically, we’ll send a GET request to this url: https://api.mathjs.org/v4/?expr=42
Now we can update the someMethodFromService function definition inside somedata.service.ts,
to this:

1 someMethodFromService(): number {
2 return this.http.get('https://api.mathjs.org/v4/?expr=42');
3 }

However, the above code update will result in an error message.


This is an example where error messages in Angular actually do work, and guide us to the solution.
Let’s see how it plays out.
First, when we update the someMethodFromService() as described above, we get the following error:
Chapter 6: Services 74

1 Type 'Observable<Object>' is not assignable to type 'number'.

So let’s try to update our method to the following:

1 someMethodFromService(): Observable {
2 return this.http.get('https://api.mathjs.org/v4/?expr=42');
3 }

Now we get a different error, with the Observable keyword underlined with a squiggly red line -
signifying the offending code. When we hover over it, the error now reads:

1 Generic type `Observable<T>` requires 1 type argument(s).

Ah, so that’s what we need to do: we need to specify the actual returned type instead of a <T>. In
other words, we need to do this:

1 someMethodFromService(): Observable<Object> {
2 return this.http.get('https://api.mathjs.org/v4/?expr=42');
3 }

Now all our errors are gone, as far as our someMethodFromService() is concerned.
However, we still need to fix another error, which we can see in the console.
Namely, this:

In app.component.ts, type ‘Observable<Object>’ is not assignable to type ‘number’

Let’s fix this error, next.

6.2.1 Fixing the error: observable object is not assignable to type


number
To understand what’s happening with this error, let’s take a step back and stop our Angular server
by simply closing the console application.
Now let’s reopen it, navigate to the folder where our Angular app lives, and restart the server with
ng serve.

Note: It might happen that you have many files on your machine and it’s kind of unclear exactly
where you’ve saved your Angular project. In that case, there’s a roundabout way of getting
Chapter 6: Services 75

where you need to be. Open VS Code, then click File > Open Recent > …, and you’ll see a list
of recently open folders and files. In my case, the first entry (the most-recently opened one), is:
∼/angulartestapp/my-app. Once you’ve reopened the files, right-click on any file in the sidebar of
VS Code, and click on “Open Containing Folder”. Once inside this folder, if needed, navigate to your
project’s root folder, i.e to the my-app folder. Now you can right-click anywhere in the blank space
of this root folder in your file explorer, and click on the “Open in Terminal” command. This will
open your terminal in the root of your Angular app, and now you can simply run ng serve.
Your Angular app will not serve since we had the error the last time we ran it. This time, instead of
seeing the app in the browser, we’ll have the following screen:

The cannot GET error in our browser

Now that we see this error on re-start, it time to update our code so that we’re error free and
everything works again.

6.2.1.1 Getting our Angular app to work again

Let’s start by reverting a part of our changes in somedata.service.ts, as follows:

1 someMethodFromService(): number {
2 return 42
3 }

Great, our app works again, and loads in the browser!


Now let’s take things a step at a time.
First, let’s verify that the API link works: https://api.mathjs.org/v4/?expr=42.
If we load the above URL in the browser, we’ll see the number 42 displayed on the screen. Great!
Let’s try a different number, for example, 40:
Chapter 6: Services 76

1 https://api.mathjs.org/v4/?expr=40

Excellent, this works as well.


Now that we’ve verified that our API URLs are correct, let’s keep going.

6.2.1.2 Subscribing to our Somedata service from app.component.ts

One of the reasons why our code does not work is due to the fact that:
To consume a service in our app.component.ts, we must subscribe to it.
This is a broad subject, but let’s not get too technical here - instead, we’ll just make it work.
Let’s open app.component.ts and locate the randomWidthAndCustomColor() method definition. We’ll
update it as follows:

1 randomWidthAndCustomColor() {
2 this.border = this.data.someMethodFromService().subscribe(res => {
3 console.log(res);
4 });
5 // ... code truncated for clarity ...

This update will now cause our border property to highlight as broken (erroneous code), so let’s
update that as well:

1 border: any;

What we did above is: we’ve set the border property to accept any type, and we’re also not assigning
it any value. We’re just declaring a variable, without a value, but whose type definition accepts any
type. This makes it less error-prone, but also less precise. Another big topic that we’ll skip for now,
just so that we can debug our app.

6.2.1.3 Defining our data model

Next, we’ll define our data model, by adding a new folder to our app. We’ll call that folder models,
and this will be its path: src/app/models.
Inside the models folder, we’ll add a new file, and we’ll call it numberFromService.model.ts.
Here’s our new file’s contents:
Chapter 6: Services 77

1 export interface NumberFromService {


2 number: number;
3 }

Now let’s save all the changes, and we’ll get the following result in the browser:

Returning number 42 from the service in the console

Great, our app works again! We’re error-free, although it’s not doing exactly what we want. Let’s
fix that next.

6.2.2 Binding the value returned from the service to the value of
this.border in the randomWidthAndCustomColor() method in App
Component’s Class file
We’re getting closer to our goal. The next step in our solution is to update the definition of
randomWidthAndCustomColor() to this:
Chapter 6: Services 78

1 randomWidthAndCustomColor() {
2 this.data.someMethodFromService().subscribe(res => {
3 this.border = res;
4 });
5 this.color = '#'+Math.random().toString(16).substr(-6);
6 }

Now our res result from the subscribe() call:

• gets assigned to the value of this.border, and


• the UI updates to show this border on the table element

Now we can finally get a random number from the API call.

6.2.3 Getting a random number from the API call


We’ll reuse some of the code we’ve used previously in this book - namely the code to randomly
generate a number using plain JavaScript.
We’ll acheive this by updating our one service as follows:

1 someMethodFromService(): Observable<Object> {
2 const params = Math.round(Math.random()*100);
3
4 return this.http.get(`https://api.mathjs.org/v4/?expr=${params}`);
5 }

This fixes our code and makes everything work again.

Every click on the button results in a new border width on our table
Chapter 6: Services 79

It’s high time for another commit, so let’s add all our changes to git and save it with the following
commit message: 6.3 Make the service dynamically provide a random number from a 3rd-party API
and consume it in the frontend of our app²⁰.
This wraps up chapter 6: Services.
In the next chapter, we’ll revise what we’ve learned in this book and we’ll discuss some of the things
that we’ve skipped.
²⁰https://github.com/ImsirovicAjdin/angular-book-1/commit/2890d61e990d629365c6bad1a00df28cb883944e
Chapter 7: Revision
Angular is a mature and stable framework that offers a lot out-of-the-box.
While the learning curve might be a bit steep, it offers great DX (developer experience) and a way
to streamline your team’s work.
A funny anecdote I’ve read online has to do with a small company of about 50 developers where
half of the employees were working with Angular, and the other half was working with React.
One of the Angular developers wrote that while they were constantly delivering their projects on
time, and had enough energy left to go grab some beers from time to time after office hours, the
React team was having to do overtime work most of the time - and of course, had to debug weird
issues instead of relax a bit.
Obviously, the above story is anecdotal, but I have a hunch it might be true.
Out of all the frontend frameworks I’ve worked with, Angular takes the high runner-up position -
i.e the second place.
The first place, as far as DX is concerned, still goes to the Elm language, but that’s a topic for another
book.
Due to its popularity and relative ease of use and its streamlined approaches, I’d even say that
Angular might share place number one with Elm - at least in my experience.
Anyway, enough with singing praises to Angular.
Let’s review what we’ve learned in this book.

A revision of things we’ve learned


Here’s a non-conclusive list of the things we’ve learned, chronologically:

1. Angular is a grouping of pre-built code that helps us build websites


2. There are two kinds of Angular (the “old” one called Angular.js and the “new” one, simply
called Angular)
3. To use Angular we need to have Node.js and NPM installed
4. We also need to have Angular CLI installed1
5. To build a new Angular app we use this command in the console: ng new ourappname (where
ourappname is the part we can change)
6. ng s serves our app in the browser
7. We can view our app at localhost:4200
Chapter 7: Revision 81

8. To check what version of Angular is installed on our machine, we run ng --version


9. To automatically update our version of Angular, we run ng update
10. When running ng new someapp we can choose if we want to use routing and we can decide
between various styling options
11. Each Angular component consists of the Class file, the Template file, the CSS file, and is
wrapped up by a module file.
12. Multiple Angular components can “live” in the same module.
13. The Class file of an Angular’s component has the following structure: import-decorator-export
14. The @Component decorator is given properties using an object literal. This decorator adds some
meta information about our component, and is used internally by Angular to put together a
working app.
15. The Class file defines the logic of our component
16. The Template file defines the ui of our component
17. Variables are displayed in template files using the moustache syntax: {{}}
18. The app.module.ts file’s structure is as follows: the import - the @NgModule Decorator - the
export. Actually, all modules follow this structure.
19. The @NgModule decorator describes how to compile a given Module and all its components. It
has the following properties: declarations, imports, providers, bootstrap
20. The Router (e.g app-routing.module.ts) is a service
21. The app-routing.module.ts Router has this structural pattern: the imports - the routes - the
@NgModule decorator - the export
22. An Angular app is mounted inside the index.html file, in the <app-root></app-root> element
23. Our Angular apps built with ng new someapp come pre-bundled with Git, and a single commit
24. To generate a component, we can run ng generate component componentname, or more
succinctly: ng g c componentname - where we can change the componentname to whatever
works for us
25. The above command generates 4 new files, and updates the app.module.ts file automatically
26. Each newly generated component has its own subfolder
27. Each component in Angular goes through a life-cycle, and we can add our own code to each
of the predefined stages of this life-cycle using lifecycle hooks.
28. An example of a lifecycle hook is ngOnInit()
29. Once the new component has been defined and the module updated, it can be added as a
sub-component to a “parent” component through the “parent” component’s template (e.g “the
navigation component to the App Module”)
30. When we generated a component, Angular automatically updated app.module.ts, by import-
ing it and listing it inside the declarations in the @NgModule decorator of app.module.ts
31. We can style each component individually
32. To target a parent, we can use the :host style selector
33. We don’t have to use a generator, we can write an Angular component from scratch.
34. We can add global styles to ./src/styles.css
35. We use routerLink in Angular instead of the href attribute in anchors
36. Each route is defined as an object inside the routes array in app-routing.module.ts file
Chapter 7: Revision 82

37. Each such object has two properties: path and component
38. There are several ways to bind template files to class files - this is data binding.
39. We can data-bind in tree ways, through: 1. interpolation, 2. event binding, and 3. property
binding
40. We bind events using round brackets: ()
41. We bind properties using square brackets: []
42. We set the values of data in our component’s Class file, e.g border = 10
43. We can dynamically update HTML attributes in our templates using property binding and
method calls in our class files
44. We can bind properties to button clicks by updating properties inside the methods called by
click events
45. Variable interpolation, property binding, and event binding are all examples of one-way data
flows
46. We can use the “banana in a box” syntax ([()]) to achieve two-way binding
47. We provide data to our angular apps using services
48. A service is generated using this code: ng generate service someservice, where the
someservice part is editable
49. The above command can be shortened to ng g s someservice
50. Data is provided through methods in our services
51. When we define a method in a service, we need to provide the expected return value of that
method
52. We use HttpClient to access third-party APIs (online data sources)
53. Angular errors can sometimes nudge us to successful debugging of our Angular apps
54. To consume a service in our component’s class file, we must subscribe to a service using the
syntax: this.data.someMethodFromService().subscribe(res => { // do something with
res here })
55. We use data model files to define the expected structure of our data, in an interface
56. To bind the value returned from a service, we assign whatever was the result of the subscription
to the property that we want to update. For example: this.border = res, where this.border
is the border property declared on the Class file and bound to in the Template file, and the res
variable is the result of the subscribe() call.

A revision of things we glossed over


We glossed over quite a number of things in this book.
The most important concepts are:

• Observers and observables


• Subscriptions
• Data models
• Building more complex apps
Chapter 7: Revision 83

Unfortunately, we couldn’t fit all of these concepts in such a short book like this one, without making
it a lot more theoretical (and a lot longer).

Explanation of the reason why this book was written


the way it was
The focus of this book is on practicality. I wanted to write a book that would give the most value to
its readers in the shortest amount of time.
Here are a few things to consider regarding this concept:

1. This book comes with its own repo. I’ve referenced this repo throughout the book, and it should
serve as a quick way to check against your own errors as you read it.
2. The goal was to make this book into a tool that would give a complete Angular newbie a chance
to get to some level of comfort with Angular, in a neat and practical package. I dare say that
this entire book can be read, cover from cover - while following examples - in about 5-6 hours.

The above two considerations make this book very useful if you’re faced with the following
situations:

• you are a new developer in an Anglar team and need to get up to speed quickly
• you need to cram for an exam involving Angular
• you need to quickly get to some level of competence with Angular for a job interview

Obviously, this book opens more doors than it closes.


It’s my attempt at giving the best bang for not only the buck, but also for the time invested.
There’s many Angular materials online that are simply too complex to grasp, and take too much
time to go through.
Hopefully, I’ve achieved my goal with this one.

Additional explanation
In early 2018, I set out to write an in-depth book on JavaScript basics.
This single book soon turned out to be over a thousand pages long, so I’ve split it into three books.
Again, these three books started getting a bit on the heavy side, so I’ve again split them into the total
of five books.
It’s 2021, and those books are still in progress.
Chapter 7: Revision 84

I’ve learned one thing from this experience.


Maybe it’s better to sometimes write books that go for quick wins.
Not that anything is inherently wrong with my JS books. Actually, I’m really proud of them.
But with this Angular book series, I wanted to try a different approach. I hope you liked this different
take on learning a JavaScript (TypeScript) framework, and that you’ve gotten value out of it.
If that’s the case, please shout it from the rooftops!
It’s quite a lot of work to write a book like this, and it’s not a very glamourous job. Also, you won’t
make too much money with it.
So, if you find yourself learning a lot from this book, please leave a review, or share your thoughts
with me through the following email address: [email protected].
Thank you.

What’s next?
This brings me to the topic of new books in this book series.
Currently, they are only a plan. I try not to plan too far ahead with these books - it’s not a productive
approach.
Thus, I’ve only planned to write the second book in this series, in the coming weeks/months -
depending on my workload.
Currently, I envision the Book two to cover in more depth the topics of:

1. Working with Angular Animations


2. Observables
3. Subscriptions
4. Other basics of RxJS
5. A bit more explanation on TypeScript
6. Using ngx-bootstrap and MDL with Angular

In a few words, I’m planning to continue guiding the reader through the interesting world of Angular
web development.
Till then, I wish you all the best in your life and career.

You might also like