Angular Project Development Best Code Practices

Posted By : Vijendra Kumar | 31-Oct-2018

Angular CLI
The Angular CLI has commands for creating Angular projects, creating components, modules, services, and more. If we want to generate a component, we will write:

 

ng g component example_component

 

It will generate 4 files for us. Component files, HTML files, CSS files and specification files. The last one is for testing purposes. If we don't want to create the last one, we can only add metrics: - false spec. By doing so, the angle CLI does not generate a specification file at all. This is just one of the options.
 

 

Files and Folders in Angular Project

File Naming
When creating a file, we must pay attention to the name of the file. The name must match the same pattern we first mentioned for the file characteristics, and then match the type separated by dots.
For example, home.component.ts or home.component.html or auth.service.ts
If we want to add more descriptive names to the file, we should use a hyphen ( - ) to separate the words in the name: menu-admin-user.component.ts

 

Folder Structure
Our files must be in a folder named by the function they represent. This is very important because we can easily identify the business logic that we implement in those files in the descriptive folder.

 

Class Names
When we add a name to the class, we must use the uppercase style of camel and add a suffix to indicate the type of our file:

 

export class DatepickerDirective
export class HomeComponent
export class RepositoryService

 

Angular Coding Practices
Single Responsibility Principle
Creating multiple components, services, and instructions in a single file is very important. Each file must be responsible for a single function. By doing so, we keep the files clean, easy to read and maintainable.

 

 

Using Interfaces
If we want to create a contract for our class, we should always use the interface. By using them, we can force the class to implement the functions and properties declared in the interface. Take the OnInit interface and its implementation as an example:

 

 

// OnInit Interface
export interface OnInit {
  ngOnInit(): void;
}

//Interface Implementation
export class HomeComponent implements OnInit {
    constructor() { }
    ngOnInit() {
}

 


Using interfaces is the perfect way to describe object text. If our object is an interface, then all the properties of the interface must be implemented. We should not name our interface with initial capital letters as in some programming languages.
 

 

export interface User {
    name: string;
    age: number;
    address: string;
}

 


Using Immutability
Objects and matrices are reference types in javascript. If we want to copy them to another object or matrix and modify them, the best thing to do is to do it in an immutable way.
By changing the reference type immutably, we preserve the original object and matrix and modify only their copies.
The easiest way to modify the immutability of objects and arrays is through the spread operator (…) :

 

 

// Original User Object
this.user = {
    name: 'Dzon',
    age: 25,
    address: 'Sunny street 34'
}

// Cloned object
let updatedUser = {
    ...this.user,
    name: 'Peter'
}

 


We are copying the user object in depth and then canceling the name attribute.
Let’s see how to use the spread operator with arrays:

 

public results = [10, 12, 14];
let newNumbers = [...this.numbers, 45, 56];

 


Now, if we delete or modify any number in the newNumbers array, the original array will retain all its values.
 

Constructor Usage
We should use constructors to configure dependency injection for our service, and that's it. We should not do any work in it, especially recovering data from the server. For this type of action, we have a lifecycle hook in Angular.
Although we can use service injection in the constructor:

 

private router: Router;
constructor(routerParam: Router) {
  this.router = routerParam;
}

 


The much better and the recommended way is:

 

constructor(private router: Router) {}

 


Safe Navigation Operator (?) in HTML Template
Of course, we must always use the safe navigation operator when accessing properties from objects in a component template. If the object is null and we try to access the property, an exception occurs. But if we use the save navigation (?) operator, the template will ignore the null value and access the property when the object is no longer null.

 


 
{{user?.name}}

 


Module Organization and Lazy Loading


Multi Modules in Application
Although Angular applications will work fine if we create a single module, it is recommended to divide our application into multiple modules. This method has many advantages. The project structure is better organized, easier to maintain, read and reuse, and we can use the lazy loading feature.
Routing Module
The best practice for Angular applications is to use a separate routing module for the router:

 

const appRoutes: Route[] = [
  { path: 'home', component: HomeComponent },
  { path: '404', component: NotFoundComponent }
]
 
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forRoot(appRoutes)
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

 


In our app module, now register our new routing module:

 

import { AppRoutingModule } from './app-routing.module';
imports: [
  AppRoutingModule
]

 


Lazy Loading
If we have a multi-module application, it is recommended to implement the slow loading feature. The big advantage of the lazy loading method is that we can load our resources on demand instead of loading them one at a time. This helps us shorten the start time. The module we are lazy loading will load as soon as the user navigates their route.
We will show how to configure lazy loading in our module:

 

const appRoutes: Route[] = [
  { path: 'home', component: HomeComponent },
  { path: 'owner', loadChildren: "./owner/owner.module#OwnerModule" },
]

 


In this code example, the HomeComponent component is loading enthusiasm, but the owner module and all components registered in the module are lazy loaded.
If you'd like more information about the lazy loading feature, you can read our blog post about lazy loading.


Shared module
If we have components, instructions or channels in the project that we want to share across the project, then the best way is to register them in the shared module's file. Then we need to register the shared module in the application module. It is important not to register the services we want to use globally in the shared module. We must register these services in our own function modules or application modules.
However, if we need to register the service in the shared module, the best way is to provide it by returning the static forRoot() method of the ModuleWithProviders interface:

 

imports and @NgModule and exports part...
export class SharedModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [ AnyService ]
    };
  }
}

 


Now we can register this shared module in the application module using the following syntax: SharedModule.forRoot().
Exporting the components we register in the shared module, instructions and channels are also important:

 

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [
    ErrorModalComponent,
    SuccessModalComponent,
    DatepickerDirective
  ],
  exports: [
    ErrorModalComponent,
    DatepickerDirective,
    SuccessModalComponent
  ]
})

 

Reusable Components and Decorators
Creating reusable components is one of the best techniques we can use when developing a project. We can reuse these types of components in any major component and pass data through the @Input decorator. These components can emit events using the decorators @Output and EventEmmiter classes. The following are examples of decorators @Input and @Output:

 

export class SuccessModalComponent implements OnInit {
  @Input() public modalHeaderText: string;
  @Input() public modalBodyText: string;
  @Input() public okButtonText: string;
  @Output() public redirectOnOK = new EventEmitter();
 
  constructor() { }
 
  ngOnInit() {
  }
 
  public emmitEvent(){
    this.redirectOnOK.emit();
  }

 

Using Lifecycle Hooks
The lifecycle hook is a very important part of the angle development. As long as we have the opportunity, we should use them. For example, if we need to get some data from the database as soon as we create an instance of the component, we should use the ngOnInit() lifecycle link instead of the constructor.

If we have some logic in the helper component and we want to execute the logic immediately after modifying the decorator's parameters, we can use the lifecycle hook of ngOnChanges().

If we need to clean up some resources immediately after the component is destroyed, we should use the lifecycle hook ngOnDestroy().

Although we don't have to implement interfaces to use lifecycle hooks, we'd better implement them.

Instead, implement it like this:

 

export class OwnerListComponent {
  constructor() { }
  ngOnInit() {
    this.getAllOwners();
  }

 

Instead, implement it like this:

 

export class OwnerListComponent implements OnInit {
  constructor() { }
  ngOnInit() {
    this.getAllOwners();
  }

 

Hope this will help you to understand angular good code practices. Thankyou.

 

About Author

Author Image
Vijendra Kumar

Vijendra is a creative UI developer with experience and capabilities to build compelling UI designs for Web and Mobile Applications. Vijendra likes playing video games and soccer.

Request for Proposal

Name is required

Comment is required

Sending message..