Angular, developed by Google as a re-write of AngularJS, is the most powerful framework for building dynamic programming structures. The main building blocks of Angular are modules, components, metadata, templates, data binding, services, directives and dependency injection. It has a wide spectrum of other internal platforms for designing single-page applications using HTML, CSS, and Typescript. Typescript which is a superscript of the JavaScript framework is used for developing Angular applications. By using Angular technology, we can create more compatible and robust UI applications.

This insightful blog aims to bring into focus all the vital angular best practices that would ensure optimal implementation of Angular projects for better performance and robust security.

Table of Contents

  1. What are the Features of Angular?
  2. Best Practices of Angular Development
  3. Angular Security Best Practices
  4. Conclusion

1. What are the Features of Angular?

What are the Features of Angular

1. Component-based Architecture

The Angular framework separates the UI of the entire application into independent reusable components. These components follow a hierarchical structure. We can gather elements with similar functionalities, use components directives and convert them into well-defined angular components that can be reused anywhere in the project for implementing functionality with similar business logic.

2. Angular Material

Angular Material is a complete UI solution for a compatible UI. It is a complete library of reusable UI components. It consists of several components like buttons, form controls, theming options, data tables, etc.

3. Modular Structure

The modular structure of Angular arranges the code into different modules so all services and components are divided into different groups when you construct them. In angular coding, you can separate functionality into reusable pieces of code.

4. TypeScript

One of the prominent superscripts of JavaScript is Typescript. It has many in-built libraries and provides numerous functionalities to an Angular Application.

5. Angular CLI

Angular CLI(Command Line Interface tool) helps in developing, scaffolding, testing, and deploying angular applications. It can generate a new angular application and files, execute an angular app, run tests, and build applications for their deployment.

6. Angular Router

Acquiring all in-built Routing and Navigation features, Angular works best for all businesses. Angular routers navigate from one page to another page without page reload and while routing to the other component it activates other required angular components as well.

7. Angular Universal

Your web application is more engaging and easy to use because of the usage of Angular Universal. It enables you to render web applications on the server-side which is helpful to any web application especially for improving search engine optimization performance.

2. Best Practices of Angular Development

1. Use Features of ES6

ES6 stands for ECMAScript 6 which provides new syntax and features to make code that is more modern and more clear. It is continuously modernized with new functionalities and features. ES6 features like Let and Const, Arrow Functions, Object Literals string interpolation makes JavaScript programming easier.

2. Use trackBy along with ngFor

Using only *ngFor directive without trackBy function in an angular application will remove all the DOM elements and then it will recreate the DOM elements again in the DOM tree. So even when the same data is getting used, it’ll slow the application performance when there is a lot of data. That is why it is good to use trackBy along with *ngFor directive.

In component.ts file:

trackByBookCode(index: number, book: any): string {
return book.code;
}

In component.html file:

<tr *ngFor='let book of books; trackBy:trackByBookCode'>

3. Use Lazy Loading

Lazy loading is nothing but a process of loading different modules like documents, JS, CSS, videos, images, etc. It increases the speed of the application’s load time by breaking it into multiple packets and loading them on request, Rather than using other functions to load all NgModules, lazy loading can be useful while loading the large application.

We can easily use lazy-loaded function to loadChildren instead of loading the component in AppRoutingModule routes configuration.

const routes: Routes = [
  {
    path: 'profile',
    loadChildren: () => import('./modules/profile/profile.module').then(m => m.ProfileModule)
  }
];

4. Use Index.ts

Working with the index.ts file is not necessary at all but we use it because it helps to keep all correlated files in a single location. Now instead of remembering multiple source file names, there are some tiny import statements that will fulfill the purpose.

For instance, we have to test the /test/index.ts component and it will look like the screenshot below.

export * from './test.model';
export * from './test.service';
export { TestComponent } from './test.component';

Now we can import all the files using

import { Test, TestService } from '../test';

5. Avoid ‘any’ type

Avoiding the use of ‘any’ type can potentially lower the number of unexpected issues. Also, not using any type in our application will make the refactoring uncomplicated. The problems can be restricted by typing the specific variables and keeping others away.

6. Prevent Memory Leaks in Angular Observable

When we navigate from one component to the other component, the first component is destroyed and the other component initializes. The first component was subscribed to the Observable and now the component is destroyed. This can cause memory leaks.

We can prevent this by following tips,

1. Using takeUntil()

TakeUntil keeps a check on second Observables and once the value of observables is generated then it will dispose of the subscription and the cycle gets finished.

this.authService.GetBookList()
      .pipe(takeUntil(this.ngUnsubscribe))
      .subscribe(res => {this.bookList = res;});
...
...
ngOnDestroy() {
  this.ngUnsubscribe.next();
  this.ngUnsubscribe.complete();
}

2. Using the Async pipe

It subscribes to an Observable or Promise and returns to the recent emitted value.

 <li *ngFor="let item of bookService.GetBookList() | async">
{{item.bookName}}
</li>

3. Using take(1)

It makes sure that you’re getting the data only once.

this.bookService.GetBookList()
      .pipe(take(1))
      .subscribe(res => {this.bookList = res;})

7. Avoid Logic in templates

Even when the function calls in angular templates that are technically correct, all template related business logic can be extracted into a component. It assists in unit testing and also reduces bugs in case of a template change in the future.

8. Cache API calls

Caching API calls improves performance and saves memory by limiting server requests to fetch redundant information. Some API responses may not change frequently so we can put some caching mechanism and can store those values from the API. When the same API request is made, we can get a response from the cache. Thus, it speeds up the application and also makes sure that we are not downloading the same information frequently.

9. Declare Safe Data Types

You will initially have to start by confirming the types of data and the set of values that it holds. After that only the possible values will be accepted by the variable. Instead of declaring a variable of a particular type, we can declare it as a list of possible values or a different type.

Example:

type WeekEnd = "Saturday" | "Sunday";
 
const day1: WeekEnd = "Saturday";
const day2: WeekEnd = "Sunday";
const day3: WeekEnd = "Monday";
 
// The last line will give this error: Type ‘"Monday"’ is not assignable to type 'WeekEnd'.

10. Use CDK Virtual Scroll

CDK(Component Development Kit) Virtual Scroll can be used to display large lists of elements more efficiently. Virtual scrolling enables an efficient way to simulate all values by making the height of the container element equal to the height of the total number of elements.

11. Use Environment Variables

Angular has different environment configurations to declare individual variables for all different types of environments. Development and production are default angular environments. We can even add more environments, or add new variables in existing environment files.

12. Use Lint Rules

The tslint has various inbuilt options like no-any, no-console, no-magic-numbers, etc, which can be configured in tslint.json file. It enforces the program to be decent and more consistent. It can be customized with your own lint rules and configurations. This ensures the readability and consistency of our code.

13. Maintain Proper Folder Structure

Creating and Maintaining a proper folder structure is an important factor everyone should consider before initiating any project. The folder structure should be flexible to new changes throughout development.

14. Use Proper Keywords (const vs let)

When you declare a variable if the value is not reassigned “Const” can be used to declare the value. The “let” keyword declares an input variable referenced within the template. Using these keywords makes the declaration of a variable more clear. With this, the code crispness and clarity are improvised.

15. Avoid having Subscriptions Inside Subscriptions

Technically, nested subscriptions work, but it is not the most effective way. In case, you want the value to be reused in more than one observable then you can use preferrable chaining options like combineLatest, withLatestFrom, etc rather than subscribing one observable in the subscribe block of another observable.

Example:

observable1$.pipe(
   first(1)
)
.subscribe(res1 => {
    observable2$.pipe(
        first(1)
    )
    .subscribe(res2 => {
        console.log(`${res1} & ${res2}`);
    });
});

After using withLatestFrom:

observable1$.pipe(
    withLatestFrom(observable2$),
    first()
)
.subscribe(([res1, res2]) => {
    console.log(`${res1} & ${res2}`);
});

After using combineLatest:

combineLatest(observable1$, observable2$).subscribe(
  ([res1, res2]) => {
    console.log(`${res1} & ${res2}`);
  }
);

3. Angular Security Best Practices

Angular Security Best Practices

Nowadays, Angular is the most preferable front-end framework. Majorly it is used in developing web apps all around the globe. Web Security is also important nowadays to protect a site from security attacks and data theft. Here, we discuss some best practices which help us avoid security vulnerabilities in our Angular application.

1. Preventing Cross-Site Scripting

In web applications to prevent malicious attacks, Cross-Site Scripting(XXS) for security vulnerability can be used. This process will send a script to the attacker and the user both at the same time and prevents the user from accepting the malicious script unknowingly into a trusted website.

As the website is trusted, when users open the website that malicious script also executes.

The malicious script that executes on the website may cause a problem as below:

  • The DOM tree may be changed by rewriting the HTML page.
  • Access information from cookies and sessions.
  • Attackers can send their script if the website is not escaping the HTML script Tags.

Cross-Site Scripting (XSS) attack example in a diagram:

Cross-Site Scripting (XSS) attack Angular

1. Prevent client-side XSS attacks

To prevent client-side XSS attacks avoid any modification in the DOM tree, Cause this action may lead to the execution of the malicious script. Use some concept to prevent this type of attack provided by an Angular:

1. InnerHtml property can be used with HTML markups for displaying data:

Angular automatically sanitizes all data that shows in components using the innerHTML property. Using the innerHTML property we can sanitize the server-side response before displaying it on the HTML side.

import { Component } from '@angular/core';
 
@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrs: ['./app.component.css']
})
export class AppComponent {
 htmlSnippet = 'Hello, <script>alert("Hi Tatvasoft")</script> <i>Good morning</i>';
}

In the above component, the variable HTML snippet contains HTML data which will be used in the following app.component.html file as a value of ‘innerHTML’ property.

<div>
<div>{{htmlSnippet}}</div>
<br />
<div [innerHTML]="htmlSnippet"></div>
</div>

When the above template will be loaded, the page will display like following:

Hello, <script>alert("Hi Tatvasoft")</script> <i>Good morning</i>
 
Hello, Good morning

2. Some point which you should note:

  • {{htmlSnippet}} contains interpolated data which will be kept as it is. Angular does not modify interpolated content.
  • When we assign a variable htmlSnippet to the [innerHtml] property, it will remove the script tag automatically and will display the data as per HTML content. For example, if there is one sentence in bold tag then angular will consider it unsafe and will sanitize that data by removing the scripting tag.
  • DOMSanitizer APIs can be used to avoid automatic sanitization:
  • As we discussed, angular will sanitize automatically if it found some untrusted data, we can use these types of APIs to prevent automatic sanitization.
  • bypassSecurityTrustHtml (By using this we can prevent HTML sanitization):

3. DOMSanitizer APIs can be used to avoid automatic sanitization:

As we discussed, angular will sanitize automatically if it found some untrusted data, we can use these types of APIs to prevent automatic sanitization.

4. bypassSecurityTrustHtml (By using this we can prevent HTML sanitization):

This is the template for the above component:

<div class="container">
<p>{{htmlSnippet}}</p>
<p [innerHtml]="trustedHtmlSnippet"></p>
</div>

bypassSecurityTrustUrl (By using this we can prevent URL sanitization):

# Component app.component.ts
#
import { Component } from '@angular/core';
import {DomSanitizer} from '@angular/platform-browser';
@Component({
 selector: 'app-root',
 templateUrl: './app.component.html',
 styleUrls: ['./app.component.css']
})
export class AppComponent {
 htmlSnippet = 'javascript:alert("Hello Tatvasoft!")';
 trustedHtmlSnippet;
 
 constructor(private sanitizer: DomSanitizer) {
   this.trustedHtmlSnippet = this.sanitizer.bypassSecurityTrustUrl(this.htmlSnippet);
 }
}

This is how the template looks like:

<div>
<a [href]="htmlSnippet">Click here to Untrusted URL</a>
<br>
<a [href]="trustedHtmlSnippet">Click here to Trusted URL</a>
</div>

An alert dialog box will get opened when you click the trusted URL link. Clicking untrusted URL, Angular considers that the URL is unsafe.

  • bypassSecurityTrustResourceUrl (By using this, we can prevent Resource URL sanitization)
  • bypassSecurityTrustScript (By using this we can prevent Script sanitization)
  • bypassSecurityTrustStyle (By using this we can prevent Style sanitization)

You must avoid direct use of DOM APIs as Angular recommends usage of templates:

Attackers can inject scripts with the use of ElementRef as Built-in DOM APIs for browsers that do not sanitize data automatically.

import { Component, ElementRef, Renderer2 } from '@angular/core';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  constructor(
    private elementRef: ElementRef,
    private renderer: Renderer2
  ) {
    /*this.elementRef.nativeElement.style.color = 'blue'; // Avoid this.*/
    this.renderer.setStyle(this.elementRef.nativeElement, 'color', 'blue');
  }
}

While loading the component, the alert box will appear on the screen. If we are passing innerHtml variable from bypassSecurityTrustHTML API of DomSanitizer then it will be considered as sanitized.

5. Content security policy (CSP):

In order to prevent XSS attacks, we need to settle policy for content security. The programmer needs to set CSP as part of the HTTP header. Consider the following examples:

<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

2. Prevent server-side XSS attacks

To avoid Cross-Site Scripting attacks in trusted websites, we need to prevent untrusted script/code, from injecting malicious scripts into the DOM tree.

  • At server-side processing, clear all the data which are containing HTML, javascript tags before sending them as the HTTP response.
  • You will have to limit yourself from generating Angular templates using server-side processing. This could result in the insertion of the template and thereby there will be DOM manipulation when the page starts loading into the browser.

2. HTTP-related Vulnerabilities

Cross-site request forgery (CSRF or XSRF) and cross-site script inclusion (XSSI) are two types of vulnerabilities where there could be an attack to access data from web apps.

1. CSRF (Cross-site request forgery)

Through this type of vulnerability, attackers make HTTP protocol requests to the server with help of any authenticated user of that site. The attacker works as a hidden mediator in this process.

For example, if an authenticated user is login into his/her website then the attacker will try that user to make an HTTP request by clicking some unknown link and can access secret information from that request.

If the victim user is the administrator of any site then the attacker can access all that information that can be accessed by that administrator.

For avoiding these type of attack, we can use an authentication token with a cookie,

During the HTTP request server will compare token data from the cookie and prevent access data if the token is not authorized.

2. XSSI (Cross-site Script Inclusion)

Attackers are using vulnerable scripts for this method. Don’t use any third-party script which is coming from an untrusted domain, because if it is not secure then the hacker can add any executable code to that script and while executing this script in our domain we might compromise any essential information.

Attackers can also add an API URL through a script tag. Angular has HttpClient library that can help programmers to fetch this type of convention and automatically remove the string “)]}’,\n” from all code and make it non-executable.

3. Use Route Guards on the Navigation

Firstly, we can accept or decline permission to navigate the URL requested by users by working on the route guard interface. Route guards are using a boolean concept like if they all return true value then the user can navigate to the requested URL and if any of them returns a false value then the user will be prevented to navigate that URL.

Different types of route guards:

  • CanActivate: Checks whether the component can be accessed or not
  • CanActivateChild: Checks whether the child component can be accessed or not
  • CanDeactivate: It asks for permission to discard the changes
  • CanLoad: Checks before load feature module
  • Resolve: It pre-fetch the route data to make sure that data related navigation is available or not.

Route Guard example:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
 
export class RouteGuard implements CanActivate {
 
 constructor(private router: Router) { }
 
 canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
 // If token is exist, user may login
 if (localStorage.getItem('token')) {
 return true;
 }
 
 // otherwise redirect to login page
 this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
 return false;
 }
}

Applying the same route guard in the route of the RouteModule. Following the example code, I have defined the route app.module file.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouteGuard } from './Services/routeGuard'
....
 
@NgModule({
 declarations: [
 ....
 ],
 imports: [
 RouterModule.forRoot([
 { path: '', component: HomeComponent, pathMatch: 'full', canActivate: [RouteGuard] },
 { path: 'my-profile', component: MyProfileComponent, canActivate: [RouteGuard] },
 ....
 ]),
 ....
 ],
 ....
})
export class AppModule { }

Generally, programmers are using logged-in user’s information like name, email, authentication token, etc. we store these pieces of information in local storage or window session storage.

Window session storage is more secure than local storage as it is removing user data when the browser gets close and it will prevent any third-party users (hackers) from accessing user’s data.

Use any storage to maintain data according to your project requirement but make sure that the user’s data must be cleared after the appropriate user gets logged out.

4. Keep Updating Angular Libraries

Angular is getting better day-by-day and providing updates frequently to enrich existing functionality and to give the best performance.

Updates keep coming every now and then with resolved issues and providing good security purposes, so keep updating your libraries and take maximum advantage of the angular framework to keep your systems flexible.

5. Must Avoid Usage of Templates Generated by Concatenating User Input

In most cases, normally we are using string interpolation or the recommended component configuration in an Angular application. But sometimes, there are some requirements that we need to concatenate input string to template.

For example:

import { Component, Input } from '@angular/core';
import { AdvertisementComponent } from './../advertisement/AdvertisementComponent';
 
const potentialUserInput = `
<!--
    user input to the template
-->
Hello
...
`
 
@Component({
    template: `
        <section>
            <h2>{{source.title}}</h2>
            <div>{{source.body}}</div>
        </section>
    ` + potentialUserInput
})
export class JobComponent implements AdvertisementComponent {
    @Input() source: any;
}

While using this type of concept you need to filter the user input data to prevent some attack because some attackers can send executable code for accessing information through their input (potentialUserInput) as shown in the above code.

Make your you never extract template source code by performing concatenation of user input and templates. To prevent these vulnerabilities, we can use “template injection” which is an offline mode of template compiler.

If we are using javascript then string concatenation is pretty easy. In Angular, there is an Ahead of Time compiler which compiles templates offline and converts HTML and typescript code into javascript.

ng build --aot
ng serve --aot

From Angular – compiling with Ivy ahead of Time compiler is set to true by default which is avoiding template injection.

{
  "projects": {
    "heroes-project": {
      "architect": {
        "build": {
          "options": {
            ...
            "aot": true,
          }
        }
      }
    }
  }
}

6. Avoid Making Changes in Angular Core Module Unless Absolutely Necessary

If you are changing or modifying any files of the Angular core module then this may affect the security and you might face some protection issues. Any unsure modification made in the default content of an Angular can harm existing functionalities or can change the default behavior of the current version.

So, if you want to essentially change or fix any existing problem by making pull requests, you should let the Angular community know this and they will update your changes if they do not affect any of the current features.

Conclusion

Multiple frontend developers are keen to develop innovative and seamless apps using their extensive knowledge of frameworks. With this comprehensive blog on the Angular best practices, we tried to cover all the major aspects and best practices that can be used by businesses in their development process and reap maximum benefits from it. Angular framework has empowered the development process with easy code writing, two-way data binding, simpler structure and other essential contributions that makes the task easy. If your in-house business is unable to do this, partner with experts for pioneering app development using the Angular framework.

We have presented an info-graphical representation of Angular Best Practices. Take a look:

Angular Best Practices Infographic
Want to embed this image? Please cite source to TatvaSoft.com

Share this Image On Your Site

profile-image
Vishal Shah

Vishal Shah has an extensive understanding of multiple application development frameworks and holds an upper hand with newer trends in order to strive and thrive in the dynamic market. He has nurtured his managerial growth in both technical and business aspects and gives his expertise through his blog posts.

Related Service

Know More About Our Angular Development Services

Learn More

Want to Hire Skilled Developers


    Comments

    • Leave a message...

      1. mrg

        Thank you mate.

      2. Samresh

        As a novice user of Angular framework and I found one technique of mitigating the risk of cross-site scripting and HTTP-related vulnerabilities is really helpful. I'll send an email to you guys on this subject. I hope that you guys will help. Thanks

      3. Darren

        I couldn’t leave without commenting on this blog and the special mention is to the infographic presented in the blog. The infographic crisply conveys the best practices and the simpler declaration of each important factor and table that might be helpful in preventing memory leaks in Angular apps.

      4. Navdeep

        This blog really helped me in honing my skills as an angular developer. Using Lint rules and Linting packages have just perfected my code. The use of authentication token and 2-factor authentication is one of my favorite practices for end-to-end security.

      5. Kevin Bell

        Thank you for an excellent blog. The information is amazing and interesting. This is a must-read for everyone. I really appreciate your hard work.

    Related Articles
    What is a WIX Toolset?
    Apr 15, 2021
    TeleHealth Software – Modernizing Healthcare Industry
    Apr 2, 2021
    Vue.js Best Practices and Security
    Mar 12, 2021