Angular recommendations and good practices

Alan Buscaglia
Mar 27 · 6 min read

Configuration Files:

tsconfig.json

Path Alias:

"paths":{  
"@src/*":[
"src/*"
],
"@assets/*":[
"src/assets/*"
],
"@shared/*":[
"src/app/shared/*"
]
}

angular.json

stylePreprocessorOptions:

"stylePreprocessorOptions": {
"includePaths": ["src/app/shared/styles"]
},

Configurations:

"configurations": {
"local": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.local.ts"
}
],
"optimization": false,
"outputHashing": "all",
"sourceMap": true,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
},
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}

Structure:

Barrels:

export * from './component-folder-1';
export * from './component-folder-2';
import { 
Component1,
Component2,
Component3,
Component4
} from './component-folder';

Main Structure:

Core Service:

Spinner implementation:

import { Injectable } from '@angular/core';
import { AbstractControl } from '@angular/forms';
import { MatAutocomplete, MatAutocompleteSelectedEvent, MatChipInputEvent } from '@angular/material';
import { Subject } from 'rxjs';
export interface LoaderState {
show: boolean;
}
@Injectable({
providedIn: 'root'
})
export class CoreService {
spinnerStatusState = new Subject<any>();
constructor() {}
displaySpinner(value: boolean) {
this.spinnerStatusState.next(<LoaderState>{ show: value });
}
}
}
import { Component, ChangeDetectionStrategy, OnInit } from '@angular/core';
import { CoreService } from './shared/services/core.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
show = false;
constructor(private coreService: CoreService) {}
ngOnInit() {
this.coreService.spinnerStatusState.subscribe(state => {
setTimeout(() => {
this.show = state.show;
}, 0);
});
}
}
<ng-container><span *ngIf="show"><app-spinner></app-spinner></span>
<app-navbar> <router-outlet></router-outlet> </app-navbar>
</ng-container>
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-spinner',
template: `
<div class="loading"></div>
`,
styleUrls: ['./spinner.component.scss']
})
export class SpinnerComponent implements OnInit {
constructor() {}
ngOnInit() {}
}
this.yourService.getInformation().subscribe(
response => {
...
this.coreService.displaySpinner(false);
},
error => {
...
this.coreService.displaySpinner(false);
}
);

Observables:

import { combineLatest } from 'rxjs';...ngOnInit() {
combineLatest(
this.yourService.getObservable1(),
this.yourService.getObservable2()
).subscribe(
([result1, result2]) = {
...
}
)
}
import { first } from 'rxjs/operators';...this.yourService.getObservable().pipe(first()).subscribe(...);

Custom Management of App State:

import { BehaviorSubject } from 'rxjs';
import { Injectable } from '@angular/core';
export interface ObserverArrayItem {
key: string;
observable: BehaviorSubject<any>;
}
@Injectable({
providedIn: 'root'
})
export class ObservableService {
private observerArray: ObserverArrayItem[] = [];
createObservable(key: string) {
const observable = new BehaviorSubject(null);
this.observerArray.push({ key, observable });
}
getObservable(key: string) {
const observableArrayItem = this.observerArray.find(obs => obs.key === key);
return observableArrayItem.observable;
}
emitValue(key: string, data: any) {
const observableArrayItem = this.observerArray.find(obs => obs.key === key);
observableArrayItem.observable.next(data);
}
destroyObservable(key: string) {
const selectedObservable = this.observerArray.find(obs => obs.key === key);
selectedObservable.observable.unsubscribe();
this.observerArray = this.observerArray.filter(obs => obs.key !== key);
}
}
export const NameOfYourObservable = 'observable1';
...
ngOnInit() {
this.observableService.createObservable(NameOfYourObservable);
}
...// after getting the informationthis.observableService.emitValue(NameOfYourObservable, 'Hi! im the information !!');
// when we destroy our component
ngOnDestroy() {
this.observableService.destroyObservable(NameOfYourObservable);
}
import { NameOfYourObservable } from './component-emitter-forlder';...ngOnInit() {
this.observableService(NameOfYourObservable).subscribe(...)
}

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/.

Alan Buscaglia

Written by

I'm an Engineer Front End Developer Architect with expertise in Angular with ngrx/store. Huge experience in big data flow applications.

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/.