Standards And Best Practices For Angular

1. Avoid ‘any’ type

  • Typescript is a language with type checking. There might be other circumstances, too, such when we need dynamic content or when we are unclear of the exact data type of some variables. In these cases, we may instruct typescript to accept any data type for the variable by using the data type ‘any’.
  • So using “any” all the time is not a good idea. The typescript is told to forego type checking by any. This might expose your code to expensive, difficult-to-trace, and difficult-to-debug issues.
const number_1: any = 1;
const number_2: any = 3;
const string_1: any = ‘a’;
const number_3: any = number_1 + number_2;
console.log(`Value of number_3 is:’, number_3);

// Output
Value of number_3 is 13

How we can overcome this by defining its type as mentioned below

const number_1: number = 1;
const number_2: number = 3;
const string_1: string = ‘a’;
const number_3: number = number_1 + number_2;
console.log(`Value of number_3 is:’, number_3);

// Output
Value of number_3 is 13

If we give the wrong type to any costant than we get the compile time error

const number_1: number = 1;
const string_1: number = ‘a’;
// This will give a compile error saying:
error TS2322: Type 'string'
is not assignable to type 'number'.
const string_1: number

2. Use Features of ES6

  • ES6 stands for ECMAScript 6, which offers new features and a new syntax to help programmers write more modern and intelligible code. It is always getting additional functionality and features added. With ES6 capabilities like Let and Const, Arrow Functions, and string interpolation, JavaScript programming is significantly easier.

3. Use trackBy along with ngFor

  • Any DOM elements in an angular application that just employs the *ngFor directive without the trackBy function will be destroyed and then rebuilt in the DOM tree. Hence, having a lot of data will make the software execute slower even when the same data is being used. Due to this, the trackBy and *ngFor directives ought to be combined.

In Component.ts

trackByUserCode(index: number, user: any): string {
return user.code;
}

In Component.html

*ngFor='let user of users; trackBy:trackByUserCode'>

4. Use Lazy Loading

  • Lazy loading refers to the method of loading numerous modules, including documents, JavaScript, CSS, movies, images, etc. It speeds up application load time by breaking up the program’s load time into numerous packets and loading them as necessary. When loading a big application, lazy loading might be useful rather than using other procedures to load the modules.
  • Lazy loading only loads anything when it is used. We can just utilise the loadChildren method of the lazy-loading library instead of loading the component as directed by the AppRoutingModule routes settings. Lazy loading, or loading a certain app feature only when required rather than when the app opens, is one of the best angular practises.
const routes: Routes = [{
    path: 'users',
    loadChildren: () => import('./modules/users/user.module').then(m => m.UserModule)
}];

5. Prevent Memory Leaks in Angular Observable

  • As we move from one component to the next, the first component is eliminated and the second component is initialised. The original component, which was an Observable subscriber, has been taken out. Memory leaks may come from this.

We can prevent this by following techniques

1. Using takeUntil()

  • TakeUntil monitors second Observables, and when the value of the observables is generated, it will dispose the subscription and the cycle will be complete.
this.authService.GetUserList()
      .pipe(takeUntil(this.ngUnsubscribe))
      .subscribe(res => {this.userList = res;});
...
...
ngOnDestroy() {
  this.ngUnsubscribe.next();
  this.ngUnsubscribe.complete();
}

2. Using the Async pipe

  • It returns to the most recent value that was emitted after subscribing to an Observable or Promise.
*ngFor="let item of userService.GetUserList() | async";
{{item.userName}}

3. Using take(1)

  • It makes sure that you’re getting the data only once.
this.userService.GetUserList()
      .pipe(take(1))
      .subscribe(res = {this.userList = res;})

6. Avoid logic in templates

  • Even though the function calls in angular templates are theoretically legal, all business logic associated with templates may be segregated into a single component. It facilitates unit testing and minimises problems in the case that a future template change takes place.

7. Declare Safe Datatypes

  • Verifying the categories of data and the range of values it includes will be the first stage. The variable will then only take the possible values after that. Instead of declaring a variable as a variable of a certain type, we might declare it as a list of potential values or a different type.

Example

type Roles = "Admin" | "User";

const user1: Roles = "Admin";
const user2: Roles = "User";
const user3: Roles = "Teacher";

// The last line will give this error: Type ‘"Teacher"’ is not assignable to type 'Roles'.

8. User CDK Virtual Scroll

  • CDK (Component Development Kit) (Component Development Kit) Use Virtual Scroll to more effectively portray long lists of components. Virtual scrolling successfully simulates all values by adjusting the height of the container element to equal the total of the heights of all the components.

9. Use Environment Variables

  • Angular offers a variety of environment settings to declare distinct variables for many sorts of scenarios. For development and production, Angular environments are typical. To the already-existing environment files, we may even add additional environments or variables.

10. Use Lint Rules

  • The tslint has a variety of built-in options, such as no-any, no-console, no-magic-numbers, etc., that may be customised in the tslint.json file. As a consequence, the software is compelled to improve and become more trustworthy. It may be built up with your own lint rules and preferences. This ensures the cohesion and clarity of our code.

11. Maintain proper folder structures

  • Everyone should consider the significance of designing and maintaining a proper folder structure before starting any angular project. The folder structure should be flexible enough to accommodate new developments as they happen.

12. Break large components into small reusable components.

  • It may also be viewed as a single-responsibility growth principle. Large components are difficult to manage, test, and debug. If the component develops in size, splitting it into smaller, more reusable components will reduce code duplication and make managing, maintaining, and debugging the component easier.

13. State Management

  • State management is one of the most difficult aspects of software development. Angular’s state management makes handling state transitions easier by storing the state of any type of data.
  • There are a variety of state management libraries for Angular on the market, each with a specific function, including NGRX, NGXS, Akita, and others. Prior to implementation, the best state management for our application may be selected.

Some of the advantages of utilizing state management.

  1. It allows data to be shared between multiple components.
  2. It allows for centralized state transition control.
  3. The code will be cleaner and easier to read.
  4. It’s simple to troubleshoot when something goes wrong.
  5. There are development tools that are available for tracing and debugging in state management libraries.

14. Documentation in code

  • Code documentation is a wise move. It will help a new developer to comprehend the project’s logic and readability. A smart Angular practise is to document each variable and method.

The actual task that a method performs must be specified

/**
* This is the get function
* @param age This is the age parameter
* @returns returns a string version of age
*/
function getUserAge(age: number): string {
    return age.toString();
}

in multi-line comments that accompany each method definition.

15. Single Responsibility Principle

  • Instead of grouping them all under a single ts file, it is preferable to make distinct ts files for components, templates, styles, and services. You can write clear, readable, and maintainable code if you treat each file as if it is responsible for a single functionality.

16. Using Interfaces

  • We must always use interfaces when writing a contract for our class. We may force the class to implement the properties and methods listed in the interface by using them. The HomeComponent class implements OnInit and OnDestroy, which is the greatest illustration of this when your component includes angular lifecycle hooks.
  • The best method for precisely describing the defined objects is using interfaces.

TypeScript will produce an error, enable IntelliSense for us, and begin populating an object if it does not include the properties of the interface:

export interface User {
    id: number;
    name: string;
    email: string;
    class: number;
    gender: "male" | "female";
    stream : "ECE" | "CSE" | "IT";
    status: boolean;
}

17. Change Detection Optimisations.

  1. It’s a good idea to use *ngIf to remove non-visible DOM components from the page rather than concealing them using CSS.
  2. To make your expressions quicker, move time-consuming computations inside the ngDoCheck lifecycle hook.
    Complex calculations ought to be stored for as long as feasible.
  3. To inform Angular that no modifications have been made, use the OnPush change detection function. The full change detection process can therefore be skipped.

18. Using Smart – Dumb components / Use Smart – Dumb Components Technique

  • This method makes it simpler to use the OnPush change detection technique by telling Angular that the dumb components have not changed. Smart components are used to manage states, focus on functionality, and process data through API calls. Unlike the stupid components, who are simply focused in looks, they are more concerned with how they seem.

 

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories