Featured Image
Software Development

Angular — Make your code more Consistent, Readable and Expandable

 

This blog describes some practices which can be followed in an Angular project to make the code more consistent, readable and extendable. It can also be applied to other frameworks. These are sort of recommendations instead of ‘must haves’. Let’s Go..!

1. Split ngOnInit() logic

Mostly ngOnInit lifecycle hook is used to initialize the component properties, to make HTTP requests and to subscribe to some states. 

There are 3 variables tempProperty , tempData and tempFormControl . All of these variables have different usage. The above code works perfectly fine. Also, as in our example, the component has no logic and is really small. In real-world scenarios, a component can be very large in terms of line of code and more code can be there in ngOnInit method. As you can see in ngOnInit method of our Demo-Component, all the operations are performed in the same method. It can be divided in some way, like below.

We now divided our ngOnInit method into three different methods.

  1. initialization() is used to initialize global component properties. It is not used for anything else. Its only purpose is to set the default values of component properties. That’s it.
  2. getData() is used to call an API and get the data.
  3. makeSubscriptions() is used to subscribe to Observables used in the component. For example, in our case, it is FormControl’s value-change. It can be any other Observables, like, Subject , BehaviorSubject or some state from the store if your project has NgRx.

This approach makes code more readable and extendable. It is really easy for new developers to understand where all component properties are set, where all subscriptions are defined. Also, if a new developer wants to add a new property or want to subscribe to a new observable it is easy for him/her to add it.

2. Instantiate objects in Constructor

Check the below code.

You might have recognized the inconsistency in the above snippet. There are 3 objects, statusUpdatecategoryUpdate and userUpdate.

statusUpdate is instantiated at declaration time, categoryUpdate is instantiated in the constructor() and userUpdate is instantiated in ngOnInit() method.

There are two problems here:

  1. The code is very inconsistent.
  2. For a new developer, it is really difficult to decide where to add a new subject if he/she has to.

Solution:

Now, there is only one method to instantiate all the objects of the component. The same can be implemented in the case of Services. It is not only to instantiate Subject but also can be used to instantiate FormControlFormGroup or any other classes.

3. Use CONSTANTS

Consider the following scenarios:

You define your path to the Login page as /login. This path is used everywhere in the application. For example,

  • You check the authentication in the guard and redirect the user to the Login page if one is not authenticated.
  • A user logs out from the system and you want to redirect him to the Login page.
  • A user tries to go to some unauthorized path of the system by using the URL and you want to redirect him to the Login page. Now suppose you have a requirement to change the path of Login page from /login to /user/login. 

How would you do that? You have to go to every single file and change the path just because you introduced a new word ( user ) in your path.

Solution:

Create a file named route.constants.ts and define every single path as constants.


You can use the same constants everywhere you want to redirect a user to the Login page. If you want to change the path, you just have to modify the value of a constant variable LOGIN_URL.

It is not only for paths of routes. You can use constants for your unique modal-ids, default configuration options of any library ( Date-picker, Charts, Maps ). 

4. Use enum

Consider the following scenarios:

You have a method in the service which has a signature as below:

getStatus(): 'todo' | 'in-progress' | 'done' {
   // some logic to return status
}

You use this method in your component as below:

const status: string = someService.getStatus();

You want your getStatus() method to return one of the statuses only from todo, in-progress and done. Therefore, you use union types.

But in your component, you want to assign the value returned by getStatus() method to a variable having string type. It will give the error as:

Type "'todo' | 'in-progress' | 'done'" is not assignable to type 'string'.

You might use the solution of using as to explicitly convert the return type as below:

const status: string = someService.getStatus() as string;

But if you have to use getStatus() in many components, the above solution is not a better one.

Solution:

Define an enum as below:

Modify the signature of getStatus():

getStatus(): Status {
   // some logic to return status
}

Modify the usage of getStatus():

const status: Status = someService.getStatus();

It resolves the error and you can be sure that there are only three types of statuses returned by the method.

Also, read our blog on dynamically adding/pushing and removing form fields to FormArray using reactive forms in Angular.

author
Kalpesh Shingala
I am a Fullstack Developer having expertise in architecture and development of Responsive, Performance efficient, Extendable and Browser compatible web applications by using the latest technologies like Angular and Vuejs.