My learning curve with Angular

Introduction 🖊:

Hello everyone, this a blog of my “blogging challenge 2020”, I will write about my learning curve with angular , some tricks that i tried to implement with angular and thinks that should be shared with community , I just tried to make some advancement implementation and check different use cases with different angular modules .

1) Recommended Angular project structure : ⛑

Before start coding, we should set the best-recommended project structure from the community, from a lot of blogs that I have read and recommended GitHub repositories, I think this is the most commonly used project structure

@NgModule({})export class CoreModule {constructor(@Optional() @SkipSelf() core:CoreModule ){if (core) {throw new Error("You should import core module only in the root module")}}}
@NgModule({imports: [CommonModule,FormsModule,ReactiveFormsModule,HttpClientModule,RouterModule,NgbModule,],exports: [CommonModule,FormsModule,ReactiveFormsModule,HttpClientModule,RouterModule,components,],declarations: [components, pipes, directives],providers: [],})export class SharedModule {}

2) Lazy Loading with Angular: ▶️ ◀️

Utility? ✔️✔️ ✔:

  • To improve the performance
  • Generates a better user experience by shortening load times and only loading necessary info.
export const routes: Routes = [{ path: 'admin', loadChildren: () => import(`./admin/admin.module`).then(m =>m.AdminModule) },{ path: 'auth', loadChildren: () => import(`./authentication/authentication.module`).then(m => m.AuthenticationModule) },{path: '**',redirectTo: 'auth'}]

3) TypeScript module resolution with AngularCLI:🛠

This section dedicated to explaining the module resolution strategy that we can implement with our angular project .

"paths": {"@features/*": ["src/modules/*"],"@core/*": ["src/app/core/*"],"@shared/*": ["src/app/shared/*"],"@configs/*": ["src/configs/*"],"@angular/core/src/metadata/*": ["./node_modules/@angular/core"]}

4) Sub routing : 🏹🏹

In this section, I will show you a basic example of navigation form component A in module A+ to component B in Module B+

What is Sub-routing :

Routing means navigating between the pages. , Sub-routing or Child-routing means navigation between sub-modules or form child route to another,

const routes: Routes = [{path: '',redirectTo: 'dashboard',},{path: 'dashboard',component: DashboardComponent,children: [{path: 'test',component: DashboardComponent,},],},];


This example fo routes definition in each module

import { NgModule } from '@angular/core';import { Routes, RouterModule } from '@angular/router';import { LoginComponent } from './login/login.component';import { SignupComponent } from './signup/signup.component';const routes: Routes = [{ path: '', component: LoginComponent },{ path: 'signup', component: SignupComponent }];@NgModule({imports: [RouterModule.forChild(routes)],exports: [RouterModule]})export class AuthenticationRoutingModule { }
import { NgModule } from '@angular/core';import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [{path: '',redirectTo: 'dashboard',},{path: 'dashboard',component: DashboardComponent,children: [{path: 'test',component: DashboardComponent,},],},];@NgModule({imports: [RouterModule.forChild(routes)],exports: [RouterModule],})export class AdminRoutingModule {}

5) Advanced Interceptors to our Angular project:📞

What is an interceptor :

Interceptor is a way to add some work or modification for each HTTP request or response.

constructor(private toastr: ToastrService) {}intercept(req: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> {if (!req.url.includes('error')) {return next.handle(req);}console.warn('ErrorInterceptor');return next.handle(req).pipe(retry(2),
catchError((error: HttpErrorResponse) => {if (error.error instanceof ErrorEvent) {console.error('An error occurred:', error.error.message);} else {switch (error.status) {case 400:console.log('400 Error Server !');break;case 405:console.log('405 Error Server !');break;case 500:console.log('500 Error Server !');break;case 403:console.log('403 Error Server !');break;default:console.log('Unknown  Error Server !');}}return throwError(error);})
import { Injectable } from '@angular/core';import {HttpInterceptor,HttpEvent,HttpHandler,HttpRequest,HttpResponse,} from '@angular/common/http';import { Observable } from 'rxjs';import { map } from 'rxjs/operators';@Injectable()export class ConverterInterceptor implements HttpInterceptor {intercept(req: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> {if (!req.url.includes('/api/csv')) {return next.handle(req);}console.warn('ConvertInterceptor');return next.handle(req).pipe(map((event: HttpEvent<any>) => {if (event instanceof HttpResponse) {// --Convert body from csv to jsonconst jsonData = this.CsvToJSON(event.body);const modifiedBody = event.clone({ body: jsonData });return modifiedBody;}}));}CsvToJSON(csv) {const lines = csv.split('\n');const result = [];const headers = lines[0].split(',');for (var i = 1; i < lines.length; i++) {const obj = {};const currentLine = lines[i].split(',');for (let j = 0; j < headers.length; j++) {obj[headers[j]] = currentLine[j];}result.push(obj);}return JSON.stringify(result);}}
import { Injectable } from '@angular/core';import {HttpInterceptor,HttpEvent,HttpHandler,HttpRequest,HttpResponse,} from '@angular/common/http';import { Observable, of } from 'rxjs';import { tap } from 'rxjs/operators';@Injectable()export class CacheInterceptor implements HttpInterceptor {private cache = new Map<string, any>();intercept(req: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> {if (!req.url.includes('/api/cache')) {return next.handle(req);}console.warn('CacheInterceptor');if (req.method !== 'GET') {return next.handle(req);}const cachedResponse = this.cache.get(req.url);if (cachedResponse) {return of(cachedResponse);}return next.handle(req).pipe(tap((event) => {if (event instanceof HttpResponse) {this.cache.set(req.url, event);}}));}}

7) Auth Guard :

  • CanActivateChild: checks to see if a user can visit a route’s children.
  • CanDeactivate: checks to see if a user can exit a route.
  • Resolve: performs route data retrieval before route activation.
  • CanLoad: checks to see if a user can route to a module that is lazy loaded.
canActivateChild(next: ActivatedRouteSnapshot,state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {// redirect and return falseif (!this.auth.isSuperAdmin) {this.router.navigate(['']);return false;}return true;}
const routes: Routes = [{path: '',redirectTo: 'dashboard',},{path: 'dashboard',component: DashboardComponent,children: [{path: 'super-user',component: SuperUserComponent,canActivateChild: [AdminGuard],},],},];

8) Rxjs 📕 :

Whats is Rxjs 📕 :

RxJS is a javascript library that brings the concept of “reactive programming” to the web.

Some Rxjs operations:

  • Observable :
search(term:string): Observable<SearchItem[]> {
let apiURL = `${this.apiRoot}?term=${term}&media=music&limit=20`;
return this.http.get(apiURL)
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { forkJoin } from 'rxjs'; // RxJS 6 syntax

export class DataService {

constructor(private http: HttpClient) { }

public requestDataFromMultipleSources(): Observable<any[]> {
let response1 = this.http.get(requestUrl1);
let response2 = this.http.get(requestUrl2);
let response3 = this.http.get(requestUrl3);
// Observable.forkJoin (RxJS 5) changes to just forkJoin() in RxJS 6
return forkJoin([response1, response2, response3]);
import { Http } from '@angular/http';import { Injectable } from '@angular/core';import { Observable } from 'rxjs/Rx';@Injectable()export class SearchService {constructor(private http: Http) {}search(term: string) {let tryCount = 0;return this.http.get('' + term + '&type=artist').map(response => response.json()).retry(3);}}
providedIn: 'root'
export class ApiService {

private SERVER = "";

constructor(private httpClient: HttpClient) { }

handleError(error: HttpErrorResponse) {
let errorMessage = 'Unknown error!';
if (error.error instanceof ErrorEvent) {
// Client-side errors
errorMessage = `Error: ${error.error.message}`;
} else {
// Server-side errors
errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
return throwError(errorMessage);

public fetchData(){
return this.httpClient.get(this.SERVER).pipe(catchError(this.handleError));

9) Never forgot to write Clean Code : ❎

Next Step Add state management to my App?

Conclusion :

In conclusion

<script>alert('try your best')</script>