Angular Architecture in a Nutshell šŸ”®

Mihlali Jordan
8 min readJul 13, 2020

Hi you! I sure am glad to see you šŸ˜ƒ! So this is actually my first blog post. As a developer I thought it would be pretty cool to share my thoughts and explain some concepts in a simple and concise manner ā€” strip away all the complexities and really just get down to the root of a feature or concept. It will pretty much be Angular galore on this blog so any React stans might want to close this tab šŸ‘€.

Anyways, in this article we will be covering the basic architecture of Angular so letā€™s get right into the meat of things!

Soā€¦what exactly is Angular? šŸ¤”

Well in simple terms itā€™s a framework that enables you to build cool frontend applications. With Angular, you can pretty much build applications for any device; be it mobile, tablets or desktops.

Take note: Angular is not the same as AngularJS nor is it an incremental version of AngularJS. Angular was completely rewritten with improved features like Dependency Injection, dynamic loading, much simpler routing and recommends that developers use TypeScript instead of JavaScript.

Angular Architecture šŸ› 

So at first glance, Angular might seem pretty daunting because of the various different concepts you come across. I mean ā€œdependency injectionā€ sounds like something that is pretty complex and far removed from normal programming concepts. This notion however, could not be further from the truth.

The Angular architecture comprises mainly of 5 key pieces: Modules, Components, Templates, Directives and Services.

NgModules

The Angular framework makes use of libraries that are grouped as modules. These libraries are fundamentally the building blocks of an Angular application. They provide a context through which components can be created. By nature, Angular applications tend to be modular and are built by assembling various different modules. Modules can have components, services, functions and some may even have a collection of other modules ā€” these are known as library modules.

Angular has packages that are prefixed with @angular. These packages are comprised of many modules. We import whatever our application needs from library modules as follows:

import (Http, Responses) from '@angular/http'

In the above snippet of code, we import Http and Response from the library module, @angular/http which refers to a folder in the Angular package.

Note: any module that is defined to be exported can be imported into another module by referencing the filename of the module wherever you are importing it.

Components

A component is simply a class that has properties and methods that are used in the view which enable the view to interact with the component.

Note: throughout the remainder of this article as I introduce new concepts, I will add on to the definition of a component.

Letā€™s create a component class Driver that has the properties name and team and a method that returns the driverā€™s best lap time.

export class DriverComponent {
name: string;
team: string;

constructor(){
this.name = "Lando Norris";
this.team = "McLaren";
}

getBestLap(): string {
return "1:08:45";
}

Templates

You can think of templates as visual representations of the component. All a template is, is html code associated with a particular component. The template is responsible for displaying and updating data according to user events.

Here is a simple template that displays the driverā€™s name and team

<h1>Driver</h1>
<p>Driver name: {{name}}</p>
<p>Constructor: {{team}}</p>

In the preceding code, the name and team values wrapped in curly braces will be provided by an instance of the component.

Metadata

Remember earlier when we said that a component is simply a class that has properties and methods that enable it to interact with the view? Well what exactly makes a component different to a regular class? I am glad you asked. A class is turned into a component by annotating it with a @Component and passing the necessary metadata, such as selector, template or templateUrl. Angular will only consider a class as a component once metadata is attached to it.

Letā€™s revisit our previous DriverComponent class we defined earlier. Angular does not consider this class a component unless we annotate it. TypeScript enables us to decorate a class with metadata as follows:

@Component({
selector: 'driver-details',
templateUrl: 'app/driver.component.html'
})
export class DriverComponent {
...
}

In the above code snippet, we decorated the DriverComponent class with @Component and attached to it metadata selector and templateUrl. What this essentially means is that whenever Angular sees the tag <driver-details/> in the view, it will create an instance of DriverComponent and render onto the DOM, the view assigned to templateUrl which is driver.component.html.

You might have noticed me using the term decorator quite a few times in the last few paragraphs. So what exactly is a decorator šŸ¤”? It is really just a function that takes in configuration parameters that are used by Angular to create an instance of the component and render the associated view.

Data Binding šŸ”—

Data binding is one of the core responsibilities of any developer building an app. Simply put, data binding is binding data to the UI and updating any data that changes, as a result of some form of user interaction, to the UI. Angular makes data binding a very trivial task and handles it for us by coordinating components and templates. The templates will provide instruction to Angular on what it should bind and how.

There are two types of data binding in Angular: one-way data binding and two-way data binding. One-way data binding deals only with either binding data from the component to the DOM or binding data from the DOM to the component. Two-way data binding however, deals with both sides of the spectrum and binds data from the DOM to the component AND from the component to the DOM.

Letā€™s look at an example of data binding.

<div>Name: {{driver.name}} <br/>
Enter Team Name: <input [(ngModel)]="driver.team">
</div>

In the above snippet of code, driver.name deals with one-way data binding. The value of the driver name will be displayed in the view if it is available in the instance of the component. driver.team, assigned to the ngModel property of the input element, deals with two-way data binding. If the component instance has a value in the team property, it will be assigned to the input elements, and if the value is changed by the user in the input control, then the updated value will be made available in the component instance.

Directives šŸ§­

All that a directive is, is a set of instruction or guidelines for rendering a template. Any class that is decorated with @Directive to attached metadata is called a directive. There are really only two directives you should be concerned about: Structural Directives and Attribute Directives.

Structural Directives manipulate DOM elements and alter their structure by adding, removing and replacing DOM elements. Letā€™s look at an example piece of code:

<ul>
<li *ngFor="let driver of drivers">
{{driver.name}}
</li>
</ul>

Here in the above code snippet we have a list item that has a *ngFor directive which will iterate through the drivers collection object and replace the name for each driver. So essentially, in your DOM, you will have a list of all the driver names in your driver collection object.

An Attribute Directive updates the behaviour or the appearance of an element. Letā€™s look at an example:

<p [myFontSize]>Fontsize is sixteen</p> 

We need to however, implement a class annotated with @Directive along with the selector for the directive.

import { Directive, ElementRef, Input } from '@angular/core';@Directive({
selector: 'myFontSize'
})
export class FontSizeDirective (){
constructor(el: ElementRef){
el.nativeElement.style.fontSize = 16;
}
}

With the above piece of code, Angular will look for all the elements with the myFontSize directive and set the font to 16. You will notice that in our import statement we import ElementRef from the Angular core library. We make use of the ElementRef in the directiveā€™s constructor to inject a reference to the host DOM element, the element to which we applied our myFontSize directive. ElementRef grants direct access to the host DOM element through its nativeElement property.

We still need to do one more thing before we finish with our directive which is to pass the directive to the declarations metadata of @NgModule as follows:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { FontSizeDirective } from './fontize.directive';
@NgModule({
imports: [ BrowserModule ],
declarations: [
AppComponent,
FontSizeDirective
],
bootstrap: [ AppComponent ]
})
export class AppModule {
...
}

Services āš™ļø

Services donā€™t really have a complex structure or definition. You can think of them as user-defined classes that are used to solve problems. Angular services are used by components to provide functionality. As far as coding in Angular is concerned, engrain it in your head to only have template-specific code in your components. A componentā€™s responsibility is to enrich the UI/UX in the app and delegate any business logic to services. Components consume and use services.

Some examples of services could be persisting application data, logging errors and file storage. Letā€™s revisit our DriverApp. We would have a DriverService that deals with adding, editing or deleting existing drivers and retrieving a list of all the drivers available.

Services are injected into components as dependencies. Which is the perfect segue into our final concept.

Dependency Injection šŸ’‰

Sounds complex, but it really isnā€™t. So, what is dependency injection? I am glad you asked. Well, think of it this way; whenever an instance of a class is created, supplying that class with whatever it requires to function properly is called Dependency Injection.

Angular has something we call an injector which is responsible for creating service instances and injecting them into classes. The injector holds instances of the dependencies and serves them as and when required.

Components depend on services. Whenever we create a component, we create a parameter constructor that takes the service as an argument. What this means is that creating an instance of the component depends on the service parameter in the constructor. What Angular will do is request that the injector provide an instance of the service in the parameter constructor of the component. The injector will then serve the instance of the requested service if it is available. If it isnā€™t available, it will create a new instance of the requested service and serve it.

export class DriverComponent {
constructor(private driverService: DriverService){}
}

The DriverComponent has a dependency on the service injected in the constructor. When an instance of the component is created, Angular will ensure that the instance of DriverService is readily available for the DriverComponent instance to use.

So, how does the injector have any knowledge of the dependencies you want to make use of? We configure the providers metadata with the required dependencies when bootstrapping the application or when decorating the components as follows:

@NgModule({
import: [ BrowserModule ],
declarations: [ AppComponent ],
providers: [ DriverService ],
bootstrap: [ AppComponent ]
})
export class AppModule {}

In the above code snippet, we add the DriverService as a provider to the bootstrap function. The injector will then create an instance of the DriverService and keep it available for the entire application to inject wherever it is requested.

@Component({
providers: [ DriverService ]
})
export class DriverComponent {
...
}

Alternatively, you can add DriverService as a provider in the metadata of the component. The injector will then create an instance of DriverService when there is a request to create an instance of DriverComponent.

That brings us to the end of this blog post. I hope that Angular and its basic concepts donā€™t seem as daunting anymore šŸ˜‰. Please do share this with whoever you think could benefit from reading it!

See you next time!! āœŒšŸ½

--

--

Mihlali Jordan
0 Followers

Hi. I am a mocaccino addict who happens to love programming ā˜ŗļøā˜•ļø