Before reading this article, first of all, please have a look at my previous article for better understanding.
In this article, I am going to discuss 8 main building blocks of an Angular app as listed below.
- Modules
- Components
- Templates
- Metadata
- Data binding
- Directives
- Services
- Dependency injection
(Above image is taken from www.angular.io site)
ModulesA
A Module is nothing but a package similar to that in Java, or like a namespace in C#, or a header-file in C / C++. Java, C#, and C++ have their own modularity system which contains classes, interfaces, enumerations etc. The same way, Angular also has its own modularity system called NgModules which helps to organize an application into adhesive blocks of functionality. Every Angular application should have at least one NgModule and the root module is called AppModule.
In Angular, everything is a class which is decorated with different types of decorators. Each decorator gives a different meaning and responsibility to a class. For instance, if a class is decorated with an @NgModule decorator, then the class is called as a module and if a class is decorated with an @Component decorator, then the class is called as a component. Here, @NgModule and @Component are decorators. The similar way, there are a few more decorators available in Angular, each and every decorator having its own meaning and usage.
@NgModule is a decorator which accepts the metadata as its input and indicates Angular how to compile and run the module code. As I told you earlier, Module is just like a package in Java, it contains components, pipes, directives, and services etc. It has many sections as listed below, each section having its own responsibility.
- imports
This is the section where we need to import all the required modules to the application. Here, we need to remember two things,
- If we talk about root module (called AppModule), then all the created modules throughout the application need to be imported here because every application starts execution from the root module before running the application and navigating among all blocks of functionality. So, all the required modules should be imported in this section so that they will be available throughout the application level.
- If our application is very big then we have to design our application structure based on the below parameters by keeping in mind,
- Performance
- Readability
- Maintainability
- Reusability etc.
So I suggest, for each module, it is better to create a base module and create all child modules based on the functionality and import them in their respective base modules. Finally, all the base modules are imported into the root module (AppModule).
- providers
This section is responsible to make services available in all parts of the application. If we refer to the created services in this section, then they become accessible in all parts of the application. As I told you earlier, Performance is one of the key qualities of every application; so we have to keep one thing in mind,
Is the created service requires throughout the application level or only to one module of the application or only to one functionality of the application?
- If the created service is required throughout the application level, then it is better to refer the created service in the providers section of the root module.
- If the created service is required only for one of the application module, then it is better to refer it to the required base module of the Angular application.
- If the created service is required only to one of the functionality of an application, then it is better to refer it to the provider section of the component's metadata section.
- declarations
This section is responsible to refer 3 kinds of classes, namely components (if the class decorates with @Component decorator), pipes (if the class decorates with @Pipe decorator), and directives (if the class decorates with @Directive decorator).
- exports - If you want to make view classes (components, pipes, and directives) available within the same Angular module or other modules, then we have to follow two steps.
Step #1
Declare the view classes (components, pipes and directives) with export keyword.
Step #2
Refer the created view classes (components, pipes and directives) in the exports section of the Angular module.
- bootstrap
This section is responsible to bootstrap the Angular application, in other words, we can say that; the application starts execution from this statement. Only the root module should set this bootstrap property.
Sample code snippet for src/app/app.module.ts file,
- import {environment} from "../environments/environment";
- import {BrowserModule} from '@angular/platform-browser';
- import {FormsModule} from '@angular/forms';
- import {HttpModule} from '@angular/http';
- import {RouterModule} from '@angular/router';
- import {Logger, Options} from "angular2-logger/core";
-
- @NgModule({
- declarations: [
- AppComponent
- ],
- imports: [
- BrowserModule,
- FormsModule,
- HttpModule,
- AppRoutingModule
- ],
-
- providers: [{ provide: Options, useValue:{ level:environment.logger.level,store: false } },
- Logger],
- bootstrap: [AppComponent]
- })
- export class AppModule {}
We can launch our application by bootstrapping the root module which is in src/main.ts file. Sample code snippet for reference,
Component
If a class is decorated with @Component decorator, then it is called Component. This is second building block of Angular. In TypeScript, we would apply the @Component decorator to attach metadata to the class. This metadata mainly consists of the selector, template / templateUrl, style / styleUrls and providers etc.
If we want to use components in other components within the same module or other modules then we have to declare them with an export keyword so that other components can use them by injecting them using dependency injection.
Sample code snippet for reference.
- @Component({
- selector: 'my-app',
- templateUrl: './my-app.component.html',
- styleUrls: ['./my-app.component.scss'],
- encapsulation: ViewEncapsulation.None,
-
- providers: [
- SelectButtonModule, DropdownModule, CalendarModule
- ]
- export class AppComponent implements OnInit { }
Templates
We can define the component's view with a Angular feature called Templates. It is nothing but a form of HTML that tells Angular how to render the component in the web browsers.
Ex: *ngFor
Metadata
In TypeScript everything is based on class, but how can we define a class as Module, Component, Service, and Pipe etc.?
This can be possible using Metadata. Metadata tells Angular how to consider a class. In TypeScript, we attach Metadata to a class by using Decorators which tells Angular whether the class is a Module, Component, Service, and Pipe etc.
For instance, if we want to create a class of type Component, then we have to use @Component decorator. Below is the sample code snippet,
- @Component({
- selector: 'my-app',
- templateUrl: './my-app.component.html',
- styleUrls: ['./my-app.component.scss'],
- encapsulation: ViewEncapsulation.None,
-
- providers: [
- SelectButtonModule, DropdownModule, CalendarModule
- ]
- export class AppComponent implements OnInit { }
selector
This points to a CSS selector that insists Angular to create an instance of the component so that we can use this CSS selector in our HTML file. Look at the above code snippet, "my-app" is a CSS selector that we can refer in our HTML file with "<my-app></my-app>" tag.
templateUrl
It refers to the relative address of the component's HTML file.
styleUrls
It refers to the relative address of the component's CSS file.
providers
It is an array where we can inject providers of services that our created component needs.
Data Binding
Like AngularJS, Angular supports 2-way data binding. It is a mechanism for coordinating parts of an HTML template with parts of a component. There are 4 forms of data-binding syntaxes supported by Angular and as mentioned below.
(Above image is taken from www.angular.io site)
Interpolation
Interpolation starts and ends with double curly braces. If you see the above screenshot, {{value}} is of type interpolation and we can bind it to an HTML element.
For instance: <span>{{value}}</span>
Property binding
This starts and ends with square braces. If you see the above screenshot, [property]='value' is of type property binding and we can bind it to an input HTML control.
For instance: <input type="text" [maxLength]="50" />
Event binding
Like HTML control events, in Angular also we can bind events to input controls. It starts and ends with parenthesis.
For instance: <button type="button" class (click)="clickMe()">Click Me</button>
Here "(click)" is an event where "clickMe()" is a method maped to the click event.
Two-way data binding
It is the combination of Property binding and Event binding.
Two-way data binding = Property binding + Event binding
In two-way data binding, the data travels from the component with a property binding to an HTML. Every change to the HTML input control also travels back to the component and it updates the property value with the latest inputted value with the help of event binding.
Directives
If the class is decorated with the @Directive decorator, then that class will be called as Directive. Directives are dynamic in nature because when we refer the created directive in HTML file then Angular renders them to the browser according to the instructions provided by directives. Angular provides 2 kinds of directives and they are structural and attribute directives.
Structural directives
This type of directives alters the HTML layout by adding, removing or replacing elements in the browser DOM.
The below code snippet uses two built-in structural directives,
<li *ngFor="let item of items"></li>
<my-app *ngIf="items.length > 0"></my-app>
- ngFor
It tells Angular to generate the HTML tags or the custom tags/elements/controls etc. (for instance <li> tag in the above example) until the items count reaches to its last index.
- ngIf
It includes the HTML tags or the custom tags/elements/controls etc. (for instance <my-app> in the above example) to the browser DOM only if the condition satisfies.
Attribute directives
This type of directive alters the behaviour of an existing element in the browser DOM at runtime.
The ngModel directive is one of the best examples of an attribute directive which implements the two-way data binding and it modifies the behaviour of an existing element by simply setting it's display value property and responding to an event.
Angular has few more directives which alter the HTML layout structure and they are ngSwitch, ngStyle and ngClass directives.
We can also create our own custom directive based on our need but those need to be registered first in its base module or in the root module before using them. If we register the created directive in its base module then the directive is available only to that module and if we register in a root module then the created directive is available throughout the application.
Services
Service is nothing but a class with a decorator @Injectable(). Usually, we use Services to communicate with API calls, but here the question may raise; why that should be a different building block? The answer is to make it loosely coupled code, which results easy to maintain and reuse throughout application easily. If we segregate the API calls into different files with a proper and meaningful name then that can be reused where ever we need them by simply injecting them as a dependency injection and even it is very easy to extend their functionality and maintain.
Dependency injection
This is the eighth building block of Angular. This provides a mechanism to supply the required Services to a component by simply importing and injecting them to its constructor.
(Above image is taken from www.angular.io site)
We can easily identify what are the Services being used in a component by simply looking at the Constructor parameters of a component. For instance, the constructor of MyAppComponent needs MyAppService:
src/app/my-app.component.ts (constructor)
constructor(private _myAppService: MyAppService) { }
Similarly, we can add N number of dependencies to a Component's constructor as per the need basis but it is highly recommended not to inject many dependencies unless it is required because injecting many dependencies will impact the performance too.
(Above image is taken from www.angular.io site)
Note
Before trying to inject any service, the Service needs to be created and should be registered in the same component or in its base module/root module.
Sample code snippet for reference,
- @Component({
- selector: 'my-app',
- templateUrl: './my-app.component.html',
- styleUrls: ['./my-app.component.scss'],
-
- providers: [
- MyAppService
- ]
- export class AppComponent implements OnInit { }
If you want your service to be available throughout the application, then add them to the root module so that the same instance of a service can be available throughout the application.
I would appreciate your valuable feedback. Happy reading :)