Angular Architecture:
- Angular Overview
- Modules
- Components
- Services and Dependency Injection
Angular Architecture Overview
An Angular app is defined usually by multiple ngModules, but it always has a main module or root module. The app.module.ts is where the bootstrapping of the app takes place. The other modules that are not the root module are called feature modules.
Don't forget the root module has the ability import other modules.
Modules
In an Angular app, you are not just going to have ngModules. You are going to have services, components, html templates or html files, css files, and more.
Tip: It's good practice to separate your Angular application with feature modules. The feature modules will contain the code related to that feature like the components, services, css files and more. Separating your app into feature modules will not only help you have a more organized app, but also will help you to lazy load your modules which will lead to a better performance of your app 😃.
From the Angular docs:
-Declarations: The components, directives, and pipes that belong to this NgModule.
They mean you will add what is related by feature to that ngModule under that ngModule. E.g You are not going to add the stove in your master room (maybe you will lol, but it's wrong). The stove will be in the kitchen.
-Exports: The subset of declarations that should be visible and usable in the component templates of other NgModules.
Remember that you can add ngModule to other ngModule. For example if you have an ngModule with all the components from Angular Material that are being used across multiple parts of you application, you will put them in a ngModule which can be used by other ngModule.
-Imports: Other modules whose exported classes are needed by component templates declared in this NgModule.
-Providers: Creators of services that this NgModule contributes to the global collection of services; they become accessible in all parts of the app. (You can also specify providers at the component level, which is often preferred.)
You can add a service at the component level via D.I (Dependency Injection).
-Bootstrap: The main application view, called the root component, which hosts all other app views. Only the root NgModule should set the bootstrap property.
bootstrap: [AppComponent]
Here's an example of how your app.module.ts(root module) can look like with the use of other modules.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ReactiveFormsModule } from '@angular/forms';
import { NgrxModule } from './shared/modules/ngrx.module';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule,
BrowserAnimationsModule,
ReactiveFormsModule,
NgrxModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Components
When creating a new Angular app, you will see that you get a component by default: the app.component.html. This component is also added to your app.module.ts by default.
A component:
1) Can import anything needed for that component and it's view.
2) Can hold your business logic.
3) Can make the connection between your component and the view.
4) Can pass values to different components (parent, siblings, child, etc).
Templates, directives, and data binding
I see templates in angular as html with super powers. Templates not only understand html, they also understand Angular markup like directives and data from your component.
From the Angular Docs, this is a small example of a template with Angular markups:
<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<ul>
<li *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</li>
</ul>
<app-hero-detail *ngIf="selectedHero" [hero]="selectedHero"></app-hero-detail>
Note: The *ngIf, and *ngFor are directives. Where *ngFor is the way to do a loop in Angular templates and *ngIf is used to conditionally show or hide a html element.
There are multiple ways to do data binding in Angular those are:
-Event binding:
<button (click)="gotoDetail()">View Details</button>
-One way binding:
<h2 [innerText]="doctor.name"></h2>
-Two way binding:
<input [(ngModel)]="doctor.name"/>
-Interpolation:
<h2>{{doctor.name}}</h2>
To learn more about data binding: https://blog.eduonix.com/web-programming-tutorials/learn-different-types-data-bindings-angular-2/
Thanks to data binding, we have the template and the component talking with each other and, not only that, thanks to data binding we can communicate between different components! I will go more in detail about the component communication in another section.
When working with templates you have access to Pipe. Pipes are basically value formatters. Pipes will change the way your data looks like without affecting the original value. You can have custom pipes built by you or used the existing pipes that the Angular team has created.
https://angular.io/api?type=pipe
From the Angular docs:
<!-- Default format: output 'Jun 15, 2015'-->
<p>Today is {{today | date}}</p>
Services and Dependency Injection
Angular services are classes that have a very specific purpose and it's good practice to create services based on their usage. For example if you want to create a service that makes an http call to your employee data, you won't have another http call to your car's data. You can have multiple services for your components or features. By defining very clearly what your service does, it will help you to understand better how your app works and will help you be more DRY.
There are 2 kinds of services:
-Feature service: A class that performs something specific for that feature you are working on.
-Shared service: A class that performs something that needs to be reused across multiple features.
D.I (Dependency Injection)
This is a way to use our service inside of a component. By doing this, we allow our component to have access to all the functionality inside our service class.
From the Angular docs:
For any dependency that you need in your app, you must register a provider with the app's injector so that the injector can use the provider to create new instances. For a service, the provider is typically the service class itself.
The Lifecycle of D.I Using a Service
When we run the following command:
ng generate service my-service-name
The Angular CLI will create a service class with the Injectable() decorator. This decorator will allow us to use the class in this case the service to be used in another class via D.I.
From the Angular docs:
-The injector is the main mechanism. Angular creates an application-wide injector for you during the bootstrap process, and additional injectors as needed. You don't have to create injectors.
-An injector creates dependencies and maintains a container of dependency instances that it reuses if possible.
-A provider is an object that tells an injector how to obtain or create a dependency.
The Angular CLI also adds a provider to the service. If you create a service at the root level, the provider for the service you just created will look as followed:
@Injectable({
providedIn: 'root',
})
Yes, you can change this behavior by adding the service in an specific ngModule. When you do this, the service will only be available to the components inside of the ngModule where you added the service.
@NgModule({
providers: [
CarService
],
...
})
The way to do D.I in your component for a service is:
//At the top of your file
import {CarService} from '../../path';
...// more code
constructor(private carService: CarService) { }
Note: You can use D.I for other things like values, functions, etc.
To learn more about D.I take a look at: https://medium.com/@tomastrajan/total-guide-to-angular-6-dependency-injection-providedin-vs-providers-85b7a347b59f
Top comments (3)
Nice article! This is super helpful for those of us who aren't familiar with Angular's structure.
Quick note of a typo: in the first example block of the 'lifecycle of d.i.' section, you have
ng generarte service my-service-name
(extra 'r' in generate)Ohhh thanks so much! :))))
Nice! Interesting take. Coding styles are important, though I would always prefer we all have a standard so it'll be even easier for the support people to troubleshoot.
I know it's a bit shameless of me to ask but do you have a beautifier plug-in/tool for your coding style? Not everyone can just immediately practice a coding style (usually, it comes naturally).