Best of experience in creating clean and fast Angular applications
To write this article, they were encouraged by the search for JavaScript front-end developers in their company in Stavropol. Because For a long time it was not possible to find an intelligent programmer, and then we decided to launch an internship program with a lot of training material on Angular & JS.
This is a translation of a Vamsi Vempati article about his experience with a large-scale application for Trade Me written in Angular.

To date, I have already worked a couple of years on a large-scale Angular application at Trade Me. Over the past few years, our team has refined our application in terms of code writing standards and performance to bring it to the best possible state.
The article outlines the methods that we use in our project. The text is mostly associated with Angular, TypeScript, RxJs and @ ngrx / store.
In addition, some general guidelines for writing code that will help make the application more “clean” and readable will be considered.
When used
When the array changes, Angular redraws the DOM tree completely. But if you use a function
Note: a more detailed description can be found in the article by Nathanel Bazal. [eng]
When declaring variables, use
The use of let and const where appropriate makes the reason for declaring variables more understandable. It can also help identify problems when a value is randomly reassigned to a constant due to a compile-time error. It also improves code readability.
Use pipe-like statements when working with statements
Pipe-like operators include only the code that needs to be executed when importing.
It also makes it easier to find unused statements in files.
Note: Angular 5.5 and above is needed.
Avoid subscribing to monitored objects from components - instead, subscribe to them from a template.
Channels are
In addition, it does not allow components to remain static and adds errors when data changes outside the subscription.
When subscribing to observable objects, always check that you will then unsubscribe from them appropriately using such operators as
Errors from unsubscribing from observed objects will lead to an undesirable memory leak, since the observed stream remains open, probably even after the component is removed or when the user moves to another page.
Moreover, create a rule
Use
Pay attention to the use
Without a
If possible, try to load modules in the application
This will reduce the size of the downloaded application and shorten its loading time.
Continued translation in the next article. If anyone does not want to wait, then here is a link to the original article.
This is a translation of a Vamsi Vempati article about his experience with a large-scale application for Trade Me written in Angular.

To date, I have already worked a couple of years on a large-scale Angular application at Trade Me. Over the past few years, our team has refined our application in terms of code writing standards and performance to bring it to the best possible state.
The article outlines the methods that we use in our project. The text is mostly associated with Angular, TypeScript, RxJs and @ ngrx / store.
In addition, some general guidelines for writing code that will help make the application more “clean” and readable will be considered.
1) trackBy
When used
ngFor
to loop an array in templates, refer to a function trackBy
that will return a unique identifier for each element.Why?
When the array changes, Angular redraws the DOM tree completely. But if you use a function
trackBy
, then Angular will understand which element has changed, and then will make changes to the DOM only for that particular element. Note: a more detailed description can be found in the article by Nathanel Bazal. [eng]
Before
{{ item }}
After
// в шаблоне
{{ item }}
// в компоненте
trackByFn(index, item) {
return item.id; // unique id corresponding to the item
}
2) const or let?
When declaring variables, use
const
if they will not be reassigned.What for?
The use of let and const where appropriate makes the reason for declaring variables more understandable. It can also help identify problems when a value is randomly reassigned to a constant due to a compile-time error. It also improves code readability.
Before
let car = 'ludicrous car';
let myCar = `My ${car}`;
let yourCar = `Your ${car}`;
if (iHaveMoreThanOneCar) {
myCar = `${myCar}s`;
}
if (youHaveMoreThanOneCar) {
yourCar = `${youCar}s`;
}
After
// значение car не переназначено, поэтому можно его сделать константой (const)
const car = 'ludicrous car';
let myCar = `My ${car}`;
let yourCar = `Your ${car}`;
if (iHaveMoreThanOneCar) {
myCar = `${myCar}s`;
}
if (youHaveMoreThanOneCar) {
yourCar = `${youCar}s`;
}
3) Pipe-like operators
Use pipe-like statements when working with statements
RxJs
. Pipe-like operators include only the code that needs to be executed when importing.
It also makes it easier to find unused statements in files.
Note: Angular 5.5 and above is needed.
Before
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/take';
iAmAnObservable
.map(value => value.item)
.take(1);
After
import { map, take } from 'rxjs/operators';
iAmAnObservable
.pipe(
map(value => value.item),
take(1)
);
4) Sign in the template
Avoid subscribing to monitored objects from components - instead, subscribe to them from a template.
Why?
Channels are
async
automatically unsubscribed, simplifying code and eliminating the need for manual subscription management. The risk of accidental unsubscribing in a component is also reduced, which will result in a memory leak. This is fixable by using the lint rule to detect unsigned observed objects. In addition, it does not allow components to remain static and adds errors when data changes outside the subscription.
Before
// шаблон
{{ textToDisplay }}
// компонент
iAmAnObservable
.pipe(
map(value => value.item),
takeUntil(this._destroyed$)
)
.subscribe(item => this.textToDisplay = item);
After
// шаблон
{{ textToDisplay$ | async }}
// компонент
this.textToDisplay$ = iAmAnObservable
.pipe(
map(value => value.item)
);
5) Clear Subscriptions
When subscribing to observable objects, always check that you will then unsubscribe from them appropriately using such operators as
take
, takeUntil
etc.Why?
Errors from unsubscribing from observed objects will lead to an undesirable memory leak, since the observed stream remains open, probably even after the component is removed or when the user moves to another page.
Moreover, create a rule
lint
to detect observed objects from which there is no unsubscription.Before
iAmAnObservable
.pipe(
map(value => value.item)
)
.subscribe(item => this.textToDisplay = item);
After
private _destroyed$ = new Subject();
public ngOnInit (): void {
iAmAnObservable
.pipe(
map(value => value.item)
// Нам нужно прослушать объект iAmAnObservable до тех пор, пока компонент не будет удалён/разрушен
takeUntil(this._destroyed$)
)
.subscribe(item => this.textToDisplay = item);
}
public ngOnDestroy (): void {
this._destroyed$.next();
this._destroyed$.complete();
}
Use
takeUntil
to listen for changes until another observable object produces a value:iAmAnObservable
.pipe(
map(value => value.item),
take(1),
takeUntil(this._destroyed$)
)
.subscribe(item => this.textToDisplay = item);
Pay attention to the use
takeUntil
with take
in the example above. This avoids memory leaks caused by the fact that no value was assigned to the subscription before the component was removed. Without a
takeUntil
subscription, it will still be in a suspended state, until it receives its first value, but since the component has already been removed, it will never receive a value, and this will lead to a memory leak.6) Lazy loading
If possible, try to load modules in the application
Angular
only when they are used.Why?
This will reduce the size of the downloaded application and shorten its loading time.
Before
// app.routing.ts
{ path: 'not-lazy-loaded', component: NotLazyLoadedComponent }
After
// app.routing.ts
{
path: 'lazy-load',
loadChildren: 'lazy-load.module#LazyLoadModule'
}
// lazy-load.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { LazyLoadComponent } from './lazy-load.component';
@NgModule({
imports: [
CommonModule,
RouterModule.forChild([
{
path: '',
component: LazyLoadComponent
}
])
],
declarations: [
LazyLoadComponent
]
})
export class LazyModule {}
Continued translation in the next article. If anyone does not want to wait, then here is a link to the original article.