Today, we’re discussing the building blocks of Angular. Basically, Angular is written in TypeScript itself. So, it is kind of a prerequisite to know TS before starting Angular. And obviously, as Angular is written in TypeScript, if we want to write our own custom code, then surely we’ll write in TypeScript. Here is the Roadmap of Angular Series.
Building Blocks of Angular
Components
At the heart of every Angular app, we have one or more components. And in fact, in the real world, we develop complex applications with tens of components inside them. A Component encapsulates the data, html markup and the logic for a view behind the view. Angular embraces component-based architecture which allows us to work on smaller and more maintainable pieces that can also be reused in different places.
Every application must have one component which we call appcomponent or root component. A real world Angular app is essentially a tree of component starting from the appcomponent.
Modules
A module is a container for a group of related components. Every Angular app has at least one module which we call app module. As our application grows, we may want to break our modules into smaller more maintainable modules. And as the application grows, we need to divide our app module into sub smaller modules and each module is responsible for a specific section. It has related components inside them.
Components
Let’s get started with something practical.
Actually we need to follow 3 steps.
- Create the Component
- Register the component in module
- Add the element in HTML Markup
Open Visual Code and build the project and
PS > ng serve
Open the url in browser (http://localhost:4200/)
Now let’s create the component.
Create Component
Open the File Panel in Visual Studio Code and in the project directory open the ‘src’ folder > ‘app’ folder
Here we want to add the component which displays the courses. So, we create the file and name it as ‘courses.component.ts’. This is the convention we use when we’re working with Angular applications. And if the component has multiple names like ‘course form’ then we’ll separate it using hyphens ‘course-form.component.ts’
Here we starts with creating plain TypeScript class in ‘courses.component.ts’
- class CoursesComponent {
- }
So in order for Angular to see this class, we need to export it.
- export class CoursesComponent {
- }
So far, we have this plain typescript class. It is not a component. In order to convert this into component, we need to add some metadata to it that Angular understands. We use the decorator by achieve this. In Angular we’ve decorator called component that we can attach to a class to make that class a component. So we need to import this decorator on the top.
As we can see this @Component() decorator function need 1 argument. Here we’ll create the object. And in this object we’ll create 1 or more properties to tell how this component works. For example one property we use quite often is selector and we select this as css selector. If we wanna reference an element like,
Element Tag |
Selector |
<courses> |
“courses” |
<div class=”courses”> |
“.courses” |
<div id=”courses”> |
“#courses” |
So here we wanna reference an element called <courses> because with components we can extend html vocabulary. So we can define new elements like courses and inside that we’ll have the list of courses or in the future we can define a custom element, custom html element called <rating>. So finally our selector of this component is courses
-
- import { Component } from '@Angular/core';
-
-
- @Component({
- selector: 'courses'
- })
- export class CoursesComponent {
-
- }
We want the second markup to be rendered for this component.
- @Component({
- selector: 'courses',
- template: '<h2>Angular</h2>'
- })
- export class CoursesComponent {
- }
So this is the basic component in Angular.
Register Component in Module
Now the second step is to register the component in the module. Currently we’ve just one module called ‘appmodule’.
Here we have 3 import statements and 1 export statement at the bottom. And note that this class is decorated with another decorator function called @NgModule. Now don’t worry about the properties used in decorator. We’ll discuss them later on. Here we just focus on declarations, this is where we add all the components that are part of this module. So by default, when we generate an application we have 1 component called appcomponent and we can see this in app module. And here we need to add our custom component in declarations and if you’re using VS Code then we have an Extension (Auto import). It imports the header reference statement automatically where you create any class object and when you provide the reference name like we do here in declarations.
- import { CoursesComponent } from './courses.component';
- import { BrowserModule } from '@Angular/platform-browser';
- import { NgModule } from '@Angular/core';
-
- import { AppComponent } from './app.component';
-
- @NgModule({
- declarations: [
- AppComponent,
- CoursesComponent
- ],
- imports: [
- BrowserModule
- ],
- providers: [],
- bootstrap: [AppComponent]
- })
- export class AppModule { }
Add the element in HTML Markup
Now it is the time to use the component in html file. Now open app.component.html file from src > app > app.component.html
This html file is actually for to rendering the homepage when we opens the localhost:4200 in the browser. Now just comment this html code and let’s try our component in html.
- <h1>My First App With</h1>
- <courses></courses>
When Angular sees this custom element, it renders the template of our courses component. Now just save the file and webpack automatically executes. And you can open the web page and see the difference
This is how it works. And if we inspect our elements in the browser then you’ll know the structure of the angular application and how it works under the hood.
Now you might be thinking if you’re watching this above pic with focus then you’ll see
<h1 _ngcontent-c0>My First App With</h1>
Where ngcontent is coming here. So, now open the index.html page from your src here you’ll see the
<app-root> </app-root> custom html element and it is using our appcomponent, you can verify it just open app.component.ts and here you’ll see
selector: ‘app-root’
So whenever Angular sees the element like that, its going to render the template for this component inside that element.
Point
You might be thinking about the views, here we’ve different html pages in the application. We’ve 1 index.html page in src folder and we’ve custom component html files as well. And here we’ve @Component({ template: ‘’ }) decorator as well to write html in it. Actually when we run the application so our main view is actually index.html where we’re consuming <app-root></app-root> app component. And if you app.component.ts here you’re defining templateUrl of app.component.html and in app.component.html we’re consuming CoursesComponent selector <courses></courses>.
And we’ve already code our CoursesComponent and define its selector above which is courses.
Generating Components Using Angular CLI
Now there are two problems with the approach we’ve already discussed to make the custom component.
- This approach is little bit tedious. There are so many steps we need to keep in mind.
- And if we forget the second step (register the component into appmodule) then our application will break.
We can take an experiment with appmodule just remove the CoursesComponent from declaration in app.module.ts,
Now save the file and open the url (localhost:4200/) and you’ll see the blank white browser screen. And now open the browser console.
Here you’ll see the error.
Now let’s move on to a quicker and reliable way to create the Angular components. Here we use Angular CLI to generate the component. Open the VS Code Terminal.
Just like we create the new application with ng new command. We can also generate the component with ng
Statement Syntax: ng g c nameofcomponent
g for generate, c for component and then the name of component. Let’s create the component called course
Angular CLI has created the directory called course and then it created the four files inside the directory. (.css) file for style of component, (.html) for html, (.spec.ts) for unit testing of component, (.ts) which is the actual component file. Another important thing is, when we created the component it automatically updates our app module as well and register our new component here. Let’s verify the automatic update in our app module.
Now open the app module.
Look it is automatically updated. And you can see, it has reduces a lot of effort. And if you open the course component
- import { Component, OnInit } from '@angular/core';
-
- @Component({
- selector: 'app-course',
- templateUrl: './course.component.html',
- styleUrls: ['./course.component.css']
- })
- export class CourseComponent implements OnInit {
-
- constructor() { }
-
- ngOnInit() {
- }
-
- }
Here is all the boiler plate code. This is how Angular cli saves us a lot of time and effort.
Templates
Component can encapsulate data, logic, html markup for a view. And if we open our coursescomponent here we’ve just html markup but we’ve not any data or any logic. So let’s extend the example.
- import { Component } from '@angular/core';
-
- @Component({
- selector: 'courses',
- template: '<h2>Angular</h2>'
- })
- export class CoursesComponent {
- }
Now we want to encapsulate the data in the container and show it in the template markup dynamically. In template, we have double curly braces syntax to encapsulate the data and when the data changes here at runtime angular automatically updates it in the browser view as well.
- import { Component } from '@Angular/core';
-
- @Component({
- selector: 'courses',
- template: '<h2>{{ name }}</h2>'
- })
- export class CoursesComponent {
- name = "My Name Is Usama";
- }
This is what we say Data Binding.
We can’t just place the variables in html template, but we can also write the simple javascript expressions and even we can also call the method here. Let’s take an example.
In Javascript, we can add the string and concatenate the strings in template.
- import { Component } from '@angular/core';
-
- @Component({
- selector: 'courses',
- template: '<h2>{{ "My Name Is: " + name }}</h2>'
- })
- export class CoursesComponent {
- name = "Usama";
- }
We can also call the functions in template as well.
- import { Component } from '@Angular/core';
-
- @Component({
- selector: 'courses',
- template: '<h2>{{ "My Name Is: " + myName() }}</h2>'
- })
- export class CoursesComponent {
- name = "Usama";
-
- myName(){
- return this.name;
- }
- }
This is what we’re working in template markup is called string interpolation.
Directives
Now let’s display the list of courses.
- export class CoursesComponent {
- name = "Usama";
- courses = ["BIO", "MTH", "CHE", "PHY"];
- }
To display this array of courses in template, we need to perform some changes.
Change the single quote (‘) with backtick (`) in template
Now the benefit of using backtick is we can break our template on multiple lines and make it more readable.
Now let’s print the name of courses in ul in template
- @Component({
- selector: 'courses',
- template: `
- <h2>{{ name }}</h2>
- <ul>
- <li></li>
- </ul>
- `
- })
Here we need to loop on our courses array to print them in, in the individual li. Here we use directive.
Directive is used to manipulate the DOM. We can them to add a DOM element or remove an existing DOM element or change the class of the DOM element or its style and so on.
Here we use directive ngFor
- import { Component } from '@angular/core';
-
- @Component({
- selector: 'courses',
- template: `
- <h2>{{ "List of Courses" }}</h2>
- <ul>
- <li *ngFor="let course of courses">
- {{ course }}
- </li>
- </ul>
- `
- })
- export class CoursesComponent {
- courses = ["BIO", "MTH", "CHE", "PHY"];
- }
This is the special syntax of Angular where we’re iterating over the courses array just like we do in javascript or C# foreach loop. And then we show the data in string interpolation.
Here we’ve displayed the data on the screen. But keep in mind, it is showing on the screen because I’m using courses component selector in my app.component.html
<courses></courses>
Service
In our real world application, obviously data comes from the server. So here is the service in Angular to understand how to consume the data in Angular coming from the server.
Here we’ve 2 options.
- Write logic for calling an HTTP service in component
But there are a couple of problems with this approach. The first problem is that this logic has tightly coupled this component to that http endpoint. And in the future when we write the unit test in this class, we don’t want to be dependent upon live http end point because it is going to make it harder to execute those unit test.
So we need to make fake http implementation of http service.
The second issue is maybe somewhere else in the application, we need to display the list of courses like in dashboard or admin or home page. With this implementation, we need to consume our http services at multiple places.
And the third issue with this implementation is, the component should not include any logic other than the presentation logic. Details should be delegated somewhere else in the application.
- So the solution is, make a separate service class where we write the logic to retrieve the data and then we reuse this class in multiple places in the application.
Add the new file in app folder courses.service.ts
And here once again we export the TypeScript class. But we’ve not any decorator for service classes. These are just plain Angular classes.
- export class CoursesService {
- getCourses() {
- return ["BIO", "MTH", "CHE", "PHY"];
- }
- }
Now back in the component, here we are not going to consume our http service and this allows us to unit test without dependency upon that http endpoint. So while unit test in this class, we can provide the fake implementation of that service. But it is quite complicated stuff, we’ll see it later on.
Dependency Injection
Now we’ve the service to get the list of courses from the server. We need to use this service in CoursesComponent. So first of all, we need to add the constructor here in component class. With the help of constructor we initialize an object. So, here we need to create an instance of service in constructor. And if you’re not using auto import plugin of VS Code, you need to manually import the service file in CoursesComponent.
And then we need to initialize our courses in CoursesComponent with service method in the constructor.
- import { Component } from '@Angular/core';
- import { CoursesService } from './courses.service';
-
- @Component({
- selector: 'courses',
- template: `
- <h2>{{ "List of Courses" }}</h2>
- <ul>
- <li *ngFor="let course of courses">
- {{ course }}
- </li>
- </ul>
- `
- })
- export class CoursesComponent {
- courses;
-
- constructor(){
- let service = new CoursesService();
- this.courses = service.getCourses();
- }
- }
Now let’s test the application and see what’s happening there. And yes it is working fine,
However there is a problem with this implementation, first problem is CoursesComponent is tightly coupled on CoursesService and if they’re tightly coupled on each other we can’t unit test this class. The major problem is we’re creating the CoursesService() object in constructor. And the second issue is if in the future we decide to add the parameter to the constructor of CoursesService, we have to come back here and anywhere in the application where we’ve use this CoursesService, we need to add a new argument there. So everytime we add a new parameter in CoursesServices, we automatically need to add the other changes as well in the complete application.
What Should We Do?
Instead of recreating an instance of CoursesService, we can ask Angular to do that for us. So delete the object creation line and add the changes in this way.
- export class CoursesComponent {
- courses;
-
- constructor(service: CoursesService){
- this.courses = service.getCourses();
- }
- }
With this Angular is going to create an instance of CoursesComponent, it looks at this constructor and sees that this constructor has a dependency of type CoursesService. So first it automatically creates an instance of CoursesService and passes to this constructor. Now if you make any kind of changes CoursesService constructor, we don’t any need to modify all the changes in the complete application. The second benefit of this implementation is that when we’re going to unit test of this CoursesComponent instead of supplying an actual courses to this constructor, we can create the fake implementation of Service that doesn’t use http service at the backend. In other words, we’ve decoupled our courses component from courses service.
So the lesson is, if we’re creating an instance of the class in any function or in another class we’ve tightly coupled this class to that class. We can’t change this at runtime but when you add that dependency as a parameter of constructor, we’ve decoupled that class from that dependency.
Now it is not even done yet, we need to explicitly instruct the Angular to create an instance of CoursesService and pass to our CoursesComponent. This concept is called Dependency Injection. So we should instruct Angular to inject the dependency of this component into its constructor.
A lot of people think dependency injection is so complicated but it is really a $25 dollar term for a 5 cent concept. So Dependency Injection means injecting or providing the dependencies of the class into its constructor.
Angular has a DI (Dependency Injection) framework built in to it. So when we create an instance of a component, it can inject the dependency but in order for that to work we need to register the dependency
(service: CoursesService)
Somewhere in our module open the app.module.ts look at this NgModule declarator, here we have a property called providers which is set to an empty array. In this array, we need to register all the dependencies that components in this module are dependent upon; i.e. CoursesComponent is dependent upon CoursesService, so we need to register CoursesService as a provider in this module.
And if you’re using auto import than it automatically adds the reference of CoursesService class in this file.
And if you forget this step to add the reference in providers array then it doesn’t work. You can make the experiment your own by commenting out or removing this item from providers array and run the url in browser and when you open the console, you’ll see the errors.
Actually what happens under the hood?
When you register the dependency provider in the module Angular creates a single instance of that class for that entire module. So imagine in this module we’ve 100 components and half of them needs CoursesService. In the memory, we’ve only a single instance of CoursesService and angular will pass the same instance all these components. This is what we called Singleton Pattern.
So a single instance of a given object exists in the memory.
Generating Services using Angular CLI
Now let me tell you the quick way to generate the service using Angular CLI. So open the Terminal window in Visual Studio Code.
Statement: ng g s NameOfService
It generates two files for us, one is the actual service file and other one (.spec.ts) has the boiler plate code for writing unit test for that service.
Here we have something new which we’ve not seen before @Injectable declarator function. We would only need this decorator function only if the service had the dependencies in this constructor i.e.
We have the dependency of logService in the constructor.
- import { Injectable } from '@Angular/core';
-
- @Injectable({
- providedIn: 'root'
- })
- export class EmailService {
- constructor(log: LogService) { }
- }
Now in this case, we need to apply this Injectable() function on this class and this tells angular at this class, an injectable class which means Angular should be able to inject dependencies of this class into its constructor. Now we didn’t use this decorator when defining the components because when we use the component decorator. That decorator internally includes the Injectable decorator. And the property,
providedIn: ‘root’
means that this service should be created by the root application injector.
What We've Learn
Let’s make a little more practical and make something new. Here we’ll explore this result by using CLI generated component and service
So first of let’s create the component and service through Angular CLI.
- PM > ng g c author
- PM > ng g s author
Now first of let’s create the code for author service.
- @Injectable({
- providedIn: 'root'
- })
- export class AuthorService {
-
- constructor() { }
-
- getAuthors(){
- return ["Bob", "Adam", "Joff", "Scott"];
- }
- }
Components are automatically register in the app.module.ts but if we wanna register the authorservice then we need to manually register the service here.
- @NgModule({
- declarations: [
- AppComponent,
- CoursesComponent,
- CourseComponent,
- AuthorComponent
- ],
- imports: [
- BrowserModule
- ],
- providers: [CoursesService, AuthorService],
- bootstrap: [AppComponent]
- })
- export class AppModule { }
Now it is the time to consume author service in our component.
- @Component({
- selector: 'app-author',
- templateUrl: './author.component.html',
- styleUrls: ['./author.component.css']
- })
- export class AuthorComponent implements OnInit {
- authors;
-
- constructor(author: AuthorService) {
- this.authors = author.getAuthors();
- }
-
- ngOnInit() {
- }
-
- }
And here is Component decorator has templateUrl author.component.html, now come on in the author.component.html
- <h2> {{ authors.length }} Authors</h2>
- <ul>
- <li *ngFor="let author of authors">
- {{ author }}
- </li>
- </ul>
.length property is javascript property through we can get the total number of arrays. And in <li> we’re using ngFor decorator, as it is changing our DOM so it is prefixed with Asterik (*)
Now as we know that our base component is app. We’re using our sub components in base components. So come on app.component.html and place your author component selector to use it.
- <app-author></app-author>
Conclusion
Here we have discussed the building blocks of Angular. Components are where we write the logic, define the selector and html markup, services are nothing but where we get the data and consume it into the component. Here we discuss how we can remove the tightly coupling between classes and inject the dependency among them. We’ve learned how we can create the component and services through Angular CLI to make our code less buggy and make the things ready in seconds. This is how we work in Angular.