Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

Building Blocks of Angular

4.24/5 (4 votes)
6 Aug 2018CPOL16 min read 27.6K   88  
Here, we'll explore the building blocks of Angular like components, directives, modules, services, component templates. We'll explore how to make components manually and how components work in the application. We'll also see the dependency injection in Angular.

Introduction

Today, we’re discussing the building blocks of Angular. Basically, Angular is written in Typescript itself. So it is a prerequisite to know Typescript 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:

Table of Contents

In this article, we'll cover a lot of things:

Building Blocks of Angular

Components

At the heart of every Angular App, we’ve 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 called appcomponent or root component. A real world angular app is essentially a tree of component starting from the appcomponent.

Image 1

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 some practical.

Actually, we need to follow 3 steps:

  1. Create the Component.
  2. Register the component in module.
  3. Add the element in HTML Markup.

Open Visual Studio Code and build the project.

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 start with creating plain typescript class in ‘courses.component.ts’.

JavaScript
class CoursesComponent { 

}

So in order for angular to see this class, we need to export it.

JavaScript
export class CoursesComponent {

}

So far, we’ve 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 achieving this. In Angular, we’ve got a 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.

Image 2

As we can see, this @Component() decorator function needs 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 want to reference an element like:

Element Tag Selector
<courses> “courses”
<div class=”courses”> “.courses”
<div id=”courses”> “#courses”

So here, we want to 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. And the template is the markup which we render on the web page on calling this template.

JavaScript
// Import Component Decorator
import { Component } from '@angular/core';
// Apply Decorator Function to the Typescript class
@Component({
    selector: 'courses',
    template: '<h2>Angular</h2>'
})
export class CoursesComponent {
}

So this is the basic component in Angular.

Register Component in Module

Now the 2nd step is to register the component in the module. Currently, we’ve just one module called ‘appmodule’.

Image 3

Here, we’ve 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’ve 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.

JavaScript
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 time to use the component in HTML file. Open app.component.html file from src > app > app.component.html.

This HTML file is actually for rendering the homepage when we open the localhost:4200 in the browser. Now just comment this HTML code and let’s try our component in HTML.

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.

Image 4

Look, 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.

Image 5

Now you might be thinking if you’re watching this above pic with focus, then you’ll see:

HTML
<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:

JavaScript
selector: ‘app-root’

So whenever Angular sees the element like that, it's going to render the template for this component inside that element.

Point

You might be thinking about the views, here we have different HTML pages in the application. We have 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 coded our CoursesComponent and define its selector above which is courses.

Generating Components Using Angular CLI

Now there are 2 problems with the approach we’ve already discussed to make the custom component.

  1. This approach is a little bit tedious. There are so many steps we need to keep in mind.
  2. And if we forget the 2nd 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.

Image 6

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.

Image 7

Here, you’ll see the error.

Now let’s move on more quicker and in a 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.

PS > ng g c course

Image 8

Look how Angular CLI has created the directory called course and then it created the 4 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 updated our app module as well and registered our new component here. Let’s verify the automatic update in our app module.

Now open the app module.

Image 9

Look it is automatically updated. And you can see, it has reduced a lot of effort. And if you open the course component:

JavaScript
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 boilerplate 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.

JavaScript
import { Component } from '@angular/core';
@Component({
    selector: 'courses',
    template: '<h2>Angular</h2>'
})

export class CoursesComponent {
}

Now what we want is to encapsulate the data in the container and show in the template markup dynamically. In template, we’ve 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.

JavaScript
import { Component } from '@angular/core';
@Component({
    selector: 'courses',
    template: '<h2>{{ name }}</h2>'
})

export class CoursesComponent {
    name = "My Name Is Usama";
}

This is what we call Data Binding.

We can’t just place the variables in HTML template, but we can also write the simple JavaScript expressions and 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.

JavaScript
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.

JavaScript
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.

JavaScript
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 into multiple lines and make it more readable.

Now let’s print the name of courses in ul in template:

JavaScript
@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.

Directives are used to manipulate the DOM. We can use 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:

JavaScript
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.

Image 10

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.

XML
<courses></courses>

Service

In our real world application, obviously data comes from the server. Here is the service in Angular to understand how to consume the data in Angular coming from the server.

Here, we have 2 options:

  1. Write logic for calling an HTTP service in component

    But there are couple of problems with this approach. The first problem is that this logic is tightly coupled from this component to that http endpoint. And in 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 2nd 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 3rd 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.

  2. 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 don't have any decorator for service classes. These are just plain Angular classes.

    JavaScript
    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 testing 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 have 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.

JavaScript
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.

Image 11

However, there is a problem with this implementation, the 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 2nd issue is if in the future, we decide to add the parameter to the constructor of CoursesService, we’ve 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.

JavaScript
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 to CoursesService constructor, we don’t need to modify all the changes in the complete application. The 2nd benefit of this implementation is that when we’re going to unit test this CoursesComponent instead of supplying an actual course 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’re 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 passes 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 as 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. Now open the app.module.ts look at this NgModule declarator, here we’ve got 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.

Image 12

And if you’re using auto import, then 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 isn't going to work. You can do the experiment yourself 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 need CoursesService. In the memory, we’ve only a single instance of CoursesService and Angular will pass the same instance to all these components. This is what we call 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. Open the Terminal window in Visual Studio Code.

Statement: ng g s NameOfService

Image 13

It generates 2 files for us, 1 is the actual service file and other one (.spec.ts) has the boilerplate code for writing unit test for that service.

Here, we’ve something new which we’ve not seen before @Injectable declarator function. We would only need this decorator function if the service had the dependencies in this constructor, i.e.:

We’ve the dependency of logService in the constructor.

JavaScript
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 Have Learned

Let’s be a little more practical and make something new. Here, we’ll explore this result by using CLI generated component and service:

Image 14

So first of all, 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.

JavaScript
@Injectable({
  providedIn: 'root'
})

export class AuthorService {
  constructor() { }
  getAuthors(){
    return ["Bob", "Adam", "Joff", "Scott"];
  }
}

Components are automatically registered in the app.module.ts but if we want to register the authorservice, then we need to manually register the service here.

JavaScript
@NgModule({
  declarations: [
    AppComponent,
    CoursesComponent,
    CourseComponent,
    AuthorComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [CoursesService, AuthorService],
  bootstrap: [AppComponent]
})

export class AppModule { }

Now it is time to consume author service in our component.

JavaScript
@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 the Component decorator has templateUrl author.component.html, now come on in the author.component.html.

HTML
<h2> {{ authors.length }} Authors</h2>
<ul>
  <li *ngFor="let author of authors">
    {{ author }}
  </li>
</ul>

.length property is a JavaScript property through which 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, our base component is app. We’re using our subcomponents in base components. So come on app.component.html and place your author component selector to use it.

HTML
<app-author></app-author>

Conclusion

Here, we’ve 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 tight 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 things ready in seconds. This is how we work in Angular.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)