Two-Factor Authentication: How to build it in Angular app with Authy

Two-Factor Authentication: How to build it in Angular app with Authy

Two-Factor Authentication (2FA) provides web applications with an important additional layer of security, but 2FA requires the user to perform an additional action each time they log in.

Two-Factor Authentication (2FA) provides web applications with an important additional layer of security, but 2FA requires the user to perform an additional action each time they log in. This extra step can be wearying for users who sign into an application frequently. Is it possible to maintain the security provided by a second factor while making an application convenient for repeat visitors? It is with Angular, Node.js, and Twilio Authy.

Implementing a “remember me” checkbox on the login page is a convenient way for a user to indicate they are going to be a repeat visitor. Behind the scenes, an encrypted security cookie is a convenient mechanism for identifying a user who has previously checked the “remember me” box and logged in successfully from a specific machine.

With Twilio Authy and an encrypted cookie, such as a JSON Web Token (JWT), you can make the sign-in process fast and convenient while maintaining the added security provided by two-factor authentication. Your returning users will be able to access your app quickly while your app will still be protected from unauthorized access with 2FA. A JWT can offer the additional advantage of third party verification, adding an additional element of security.

Although an encrypted cookie is a great place to store securely store data on the client, the range of data should be restricted to information the user knows, like their user ID and password, or data associated with the user, like their account number and most recent order date. The security cookie is not an appropriate place for API keys or other sensitive data beyond the scope of the user’s interaction with the app.

Understanding the process

There are two common approaches shortening the sign-in process for returning users: the user can skip entering their credentials (user ID and password) or they can skip the second factor authentication. Of the two, skipping credential entry is a more secure approach because it requires the user to still be in possession of both the machine bearing the encrypted security cookie and the 2FA device, typically a smartphone. The second, more secure, technique is the one demonstrated in this post.

The process of determining a user’s login and authentication status involves both the client and the server. For new users, or users who have not previously checked the “remember me” checkbox, the app needs to create the encrypted cookie. For returning users who have a valid cookie on their current machine, the client code needs to pass data from the cookie back to the server so the server code can determine the user ID and password without requiring the user to enter them. With the user’s ID, the server can then lookup the user’s Authy ID and call the API to start the 2FA process. When the user completes the 2FA process successfully a security cookie can be created or updated.

What you’ll learn in this post

By building the project in this post you’ll learn how to add “remember me” functionality to an Angular Universal + Node.js website. The “remember me” functionality will enable returning users to log into the application by approving the authentication request on their device; they won’t need to re-enter their user ID and password, so they’ll be logged in with just one tap.

You’ll also learn how to use a cookie to transfer the data needed to implement “remember me” along with 2FA. To make this case study project less complex and easier to understand, the code in this project creates a plaintext cookie. Cookie encryption and JWT implementation will be covered in another post.

Prerequisites

To accomplish the tasks in this post you will need:

To learn most effectively from this post you should have:

  • A working knowledge of TypeScript and the Angular framework
  • Familiarity with Angular observables, dependency injection, routing, and pipes
Set up the baseline Angular 2FA project

This post uses the Angular + Node.js project from the previous post in this series: Build Two-factor Authentication in Angular with Twilio Authy. You can continue with your existing code if you have successfully built the project from the previous post.

If you haven’t built that project, or you want to start fresh one, you can clone the code from the GitHub repo for this post.

Clone it by executing the following commands in the directory where you would like to create the project directory:

git clone https://github.com/maciejtreder/angular-authy-remember.git
cd angular-authy-remember
npm install
Set up Authy and an Authy user

If you’ve already completed building the project from the previous post you can use the Authy application Production API Key and Authy ID for the user you set up as part of that exercise.

If you’re starting fresh you’ll need to get Authy and a user set up. Follow these instructions:

Once you have a Twilio account, sign in and navigate to the Authy section of the Twilio Console and complete the following steps:

  1. In the Authy section of the Twilio console, create a new application.
  2. Copy the Production API Key for the application to a safe place. (You can find the key in the Settings for the application if you misplace it.)
  3. In the application you created, register yourself as a new user using your preferred email address and mobile phone number.
  4. Copy the Authy ID for the user you just created to a safe place.
  5. Install the Authy app on your mobile phone. You should have received a text notification with a link to get the codes to complete the installation.
Add the Twilio securables to the server code

Open the angular-authy-twilio/server.ts and replace the placeholder with your Production API Key in the following constant declaration:

const API_KEY = 'Production API key';

Replace the authy_id placeholder with the Authy ID for the user you created:

authy.send_approval_request('authy id', {

Once you have added your Production API Key and Authy ID to the server.ts file, do not check it into a publicly accessible place, like a GitHub repository.

Build and test the application

Run the following instructions at the command line in the angular-twilio-authy directory:

npm run build:prod
npm run server

Open a browser window, open the browser’s developer tools (F12), and select the Network tab.

Navigate to http://localhost:8080 (or https://localhost:8080 if you’ve implemented SSL/TLS). You should see the /login page, as shown below:

Enter the credentials User ID: foo and Password: bar. Click Log In.

You should receive an authorization request in the Authy app on the device associated with the phone number you provided for the user you registered in the Authy section of the Twilio console.


Approve the request.

After authorization you should be redirected to the /home route, which is protected by the authorization guard in the application. (See the post Build Two-factor Authentication in Angular with Twilio Authy for more information on how this works.)

If this process worked as described, two-factor authentication is working in your Angular application.

Implement returning user recognition

The authorization service AuthService needs to respond differently depending on the value of the rememberfield. If the value is true and the user passes the second authentication factor, the service tells the server to include the value of the remember field in the cookie.

Open the src/app/auth.service.ts file and replace the auth and secondFactor methods with the following TypeScript code:

auth.service.ts

public auth(login: string, password: string, remember: boolean): Observable<any> {
 return this.http.post<any>('/auth/login', {login: login, password: password}).pipe(
   flatMap(response => this.secondFactor(response.token, remember) )
 );
}
public secondFactor(token: string, remember: boolean): Observable<any> {
 const httpOptions = {
   headers: new HttpHeaders({
     'Token': token,
     'Remember': '' + remember
   })
 };
 const tick: Observable<number> = timer(1000, 1000);
 return Observable.create(subject => {
   let tock = 0;
   const timerSubscription = tick.subscribe(() => {
     tock++;
     this.http.get<any>('/auth/status', httpOptions).subscribe( response => {
       if (response.status === 'approved') {
         this.redirectUrl = this.redirectUrl ? '/' : this.redirectUrl;
         this.router.navigate([this.redirectUrl]);
         this.closeSecondFactorObservables(subject, true, timerSubscription);
       } else if (response.status === 'denied') {
         this.closeSecondFactorObservables(subject, false, timerSubscription);
       }
     });
     if (tock === 60) {
       this.closeSecondFactorObservables(subject, false, timerSubscription);
     }
   });
 });
}

Encrypted cookies are created by the /auth/status endpoint on the server, so the endpoint code needs to be updated to generate the cookie and set an expiration age, maxAge, which is measured in seconds.

Open the server.ts file and replace the TypeScript code for the /auth/status endpoint with the following:

server.ts

app.get('/auth/status', (req, res) => {
  authy.check_approval_status(req.headers.token, (err, authResponse) => {
    if (err) {
      res.status(400).send('Bad Request.');
    } else {
      if (authResponse.approval_request.status === 'approved') {
        res.cookie('authentication', 'super-encrypted-value-indicating-that-user-is-authenticated!', {
          maxAge: 60 * 60,
          httpOnly: true
        });
        if (req.headers.remember === 'true') {
         res.cookie('remember', authResponse.approval_request._authy_id, {
           maxAge: 5 * 60 * 60,
           httpOnly: true
         });
       }
      }
      res.status(200).send({status: authResponse.approval_request.status});
    }
  });
});

Note that the cookie timeout set in the maxAge parameter is relatively short, 1 minute for the second-factor cookie and 5 minutes for the remember cookie. This is so the cookie persists long enough that you can see the expedited 2FA login working even when a user is signed out, but not so long there’s an old cookie sticking around and getting in the way of your end-to-end testing. If you’re building this project quickly, you may need to remove the cookie on your own to reset your browser for end-to-end testing.

Add a Remember Me control to the login page

To begin recognizing returning users the app needs a way for the user to indicate they want to be remembered. In addition to making the login process more convenient for returning users, adding a “Remember Me” control can also help build compliance with the EU General Data Protection Regulation.

The existing code has a LoginPageComponent, so it’s easy to add another control.

Replace the code in src/app/login-page/login-page.component.html with the following HTML markup:

login-page.component.html

<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
   <label>User ID: </label><input type="text" formControlName="login" /><br/>
   <label>Password: </label><input type="password" formControlName="password" /><br/>
   <label>Remember Me: </label><input type="checkbox" formControlName="remember" /> <br/>
   <input type="submit" value="log in" />
</form>
<h1>{{message | async}}</h1>

Open the src/app/login-page/login-page.component.ts file and make the following TypeScript modifications.

Add the newly created field to the loginForm FormGroup class initialization:

login-page.component.ts

public loginForm: FormGroup = new FormGroup({
 login: new FormControl(''),
 password: new FormControl(''),
 remember: new FormControl(false)
});

Add the value of the remember control to the arguments of the AuthService.auth() call in the onSubmit()method:

login-page.component.ts

public onSubmit(): void {
  this.message.next('Waiting for second factor.');
  this.authService.auth(
    this.loginForm.get('login').value,
    this.loginForm.get('password').value,
    this.loginForm.get('remember').value
  ).pipe(
  catchError(() => {
    this.message.next('Bad credentials.');
    return throwError('Not logged in!');
  })
  )
  .subscribe(response => {
    if (!response) {
      this.message.next('Request timed out or not authorized');
    }
  });
}
Test the remember cookie functionality

At this point it’s a good idea to be sure the application is correctly handling input using the new user interface element and generating the new cookie correctly.

Execute the following command line instructions in the angular-twilio-authy directory:

npm run build:prod
npm run server

Open a browser tab. Open the developer tools (F12) for the tab and switch to the Network tab so you can see the communication between the browser and the Node.js server.

Navigate to http://localhost:8080 (or https if you’ve implemented SSL/TLS).

You should see the /login page, like the one shown below.

Enter the login credentials User ID: foo and Password: bar. Check the Remember Me checkbox. Click the Log In button and watch the Network tab in your browser. You should see a series of status messages as the /auth/status endpoint returns a HTTP 200 reply and the value of authResponse.approval_request.status.

Approve the Twilio Authy authentication request on your mobile device. In the Network tab of your browser’s developer tools you should see that the last status response contains a cookie which contains an authentication field and a remember field.

In a production application the cookie and these fields would be encrypted. They are plain text in this project so you can more easily follow the behavior of the code.

The value for the remember field is the Authy ID for the user who is logging in. Although this value is hard-coded in the server.ts file to simplify this demonstration project, in a production application you would typically retrieve it from a persistent data store by querying with the user’s ID after the user’s ID and password have been validated. This prevents an Authy ID from being set in a cookie unless a valid user ID and password pair are entered.

Because the cookie is httpOnly it is not accessible from JavaScript running in the browser. And because it would be encrypted in a production app it would be difficult to access the Authy ID on a client machine. The client-side code only needs to know that the remember field in the cookie is set, not its value.

If you want to catch up to this step using the code from the GitHub repository, execute the following commands in the directory where you’d like to create the project directory:

git clone https://github.com/maciejtreder/angular-authy-remember.git
cd angular-authy-remember
git checkout step1

Add the Authy Production API Key and the Authy ID for the user you created to the code by following the instructions in the section above, Add the Twilio securables to the server code.

Execute the following npm command line instruction in the angular-authy-remember directory:

npm install

Follow the instructions at the beginning of this section to try out the Remember Me checkbox functionality.

Transferring values to the server-side rendered Angular code

Your applications should never expose production secrets such as API keys to the client-side code. To avoid hardcoding the Authy Production API Key in our application TypeScript you can use same technique as in the post How to Transfer Files and Data in JavaScript Applications Between Angular and Node.js.

Open the server.ts file and locate the following TypeScript code:

server.ts

app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
  ]
}));

Add the API_KEY constant to the list of providers in the app.engine method call it looks like the following:

server.ts

app.engine('html', ngExpressEngine({
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP),
    {provide: 'API_KEY', useValue: API_KEY}
  ]
}));

Now you can make use of the cookie set by Node.js in the part of the Angular application responsible for rendering content on the server-side. Because the cookie is httpOnly, it is not accessible to JavaScript executed in the browser. The app is going to retrieve the Authy ID of the remembered user, issue an authentication request with Twilio Authy, and provide the retrieved Authy ID to the browser by using TransferState technique. (You can learn more about using the TransferState object in the post: How to Transfer Files and Data in JavaScript Applications Between Angular and Node.js.)

Open the src/app/auth.service.ts file and add the following code to the list of ìmport directives:

auth.service.ts

import { StateKey, makeStateKey, TransferState } from '@angular/platform-browser';

Modify the AuthService constructor to inject the TransferState object with the Authy Production API Key, which is provided by Node.js.

Replace the existing constructor code in the auth.service.ts file with the following code:

auth.service.ts

constructor(
  private router: Router,
  private http: HttpClient,
  @Inject(PLATFORM_ID) private platformId: any,
  @Optional() @Inject(REQUEST) private request: any,
  private transferState: TransferState,
  @Optional() @Inject('API_KEY') private apiKey
) { }

The AuthService needs a way to determine if a remembered user has passed the second-factor validation with Twilio Authy. This process involves code for both the server and the client in an AuthService method called getRememberedToken().

The code that executes on the server calls the Twilio Authy API and invokes the Authy authentication process. If the user accepts the authentication request in the Authy app on their device, the value of the authyToken in the TransferState object is set to the user’s Authy ID.

If the code is running on the client, the Authy ID is retrieved from the TransferState object.

Add the getRememberedToken() method to the auth.service.ts file by inserting the following TypeScript code at the bottom of the class definition (before the final }):

auth.service.ts

public getRememberedToken(): Observable<string> {
 const key: StateKey<string> = makeStateKey<string>('authyToken');
 return Observable.create(subject => {
   if (isPlatformServer(this.platformId) && this.request.cookies.remember) {
     this.http.post<any>(
       `https://api.authy.com/onetouch/json/users/${this.request.cookies.remember}/approval_requests?api_key=${this.apiKey}`,
       {message: 'Log into your Angular and Authy application'}
       ).subscribe(resp => {
         this.transferState.set(key, resp.approval_request.uuid);
         subject.next(null);
         subject.complete();
     });
   } else {
     subject.next(this.transferState.get(key, null));
     subject.complete();
   }
 });
}

The application will need a resolver that implements the Angular Resolve interface. The resolver intercepts a link click and returns a value or observable which can be used in the calling method’s code.

In this application the LoginResolverService class will provide the the value returned by the getRememberedToken() method as an observable.

Generate the login resolver files by executing the following Angular CLI command at in the angular-authy-remember directory:

ng g s loginResolver --skipTests

Implement the LoginResolverService class by replacing the contents of the src/app/login-resolver.ts file with the following code:

login-resolver.ts

import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
 providedIn: 'root'
})
export class LoginResolverService implements Resolve<Observable<string>> {
 constructor(private authService: AuthService) { }
 resolve(): Observable<string> {
   return this.authService.getRememberedToken();
 }
}

The resolver will be used when users navigate to the /login page.

Open the src/app-routing.module.ts file and add the following code to the existing list of import directives:

app-routing.module.ts

import { LoginResolverService } from './login-resolver.service';

Modify the route definition for the /login path by replacing the existing line with the following code:

app-routing.module.ts

{ path: 'login', component: LoginPageComponent, resolve: {token: LoginResolverService} },

Now you can refactor the LoginPageComponent class to use the resolver and second-factor authentication.

Replace the contents of the src/app/login-page.component.ts file with the following TypeScript code:

login-page.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { AuthService } from '../auth.service';
import { BehaviorSubject, Subject, throwError, Observable } from 'rxjs';
import { catchError, finalize } from 'rxjs/operators';
import { ActivatedRoute } from '@angular/router';
@Component({
 selector: 'app-login-page',
 templateUrl: './login-page.component.html',
 styleUrls: ['./login-page.component.css']
})
export class LoginPageComponent implements OnInit {
 public message: Subject<string> = new BehaviorSubject('');
 public loginForm: FormGroup = new FormGroup({
 login: new FormControl(''),
 password: new FormControl(''),
 remember: new FormControl(false)
 });
 private authyToken: string = this.router.snapshot.data['token'];
 constructor(private authService: AuthService, private router: ActivatedRoute) { }
 public ngOnInit(): void {
   if (this.authyToken != null) {
     this.message.next('Waiting for second factor.');
     this.handleSecondFactor(this.authService.secondFactor(this.authyToken, true));
   }
 }
 public onSubmit(): void {
   this.message.next('Waiting for second factor.');
   this.handleSecondFactor(this.authService.auth(
   this.loginForm.get('login').value,
   this.loginForm.get('password').value,
     this.loginForm.get('remember').value
   ));
 }
 private handleSecondFactor(secondFactor$: Observable<boolean>): void {
   secondFactor$.pipe(
     catchError(() => {
       this.message.next('Bad credentials.');
       return throwError('Not logged in!');
     }),
     finalize(() => this.message.next('Request timed out or not authorized'))
   ).subscribe();
 }
}

The revisions to the LoginPageComponent class accomplish a number of tasks:

The OnInit interface is implemented in the LoginPageComponent class to enable use of the resolver.

An ActivatedRoute object is injected into the LoginPageComponent class so the value of authToken can be obtained from the router data.

Handling of the second authentication factor is moved to a private method, handleSecondFactor().

handleSecondFactor() receives the results of the authService.auth() method as an observable that indicates if the second factor request was authorized (true), rejected (false), or timed out (null).

handleSecondFactor() is called in two places:

  1. onSubmit() performs the initial first-factor check (user ID and password).
  2. ngOnInit() checks for the status of the second factor by using the TransferState object provided by the resolver, LoginResolverService.

The final step in building the application is refactoring the AuthorizationService class.

Replace the code in the src/app/auth.service.ts file with the following TypeScript code:

auth-service.ts

import { Injectable, Inject, PLATFORM_ID, Optional } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map, flatMap, concatMap, take, filter, takeWhile } from 'rxjs/operators';
import { Observable, timer, of } from 'rxjs';
import { isPlatformServer } from '@angular/common';
import { REQUEST } from '@nguniversal/express-engine/tokens';
import { StateKey, makeStateKey, TransferState } from '@angular/platform-browser';
@Injectable({
providedIn: 'root'
})
export class AuthService {
 private redirectUrl: string = null;
 constructor(
   private router: Router,
   private http: HttpClient,
   @Inject(PLATFORM_ID) private platformId: any,
   @Optional() @Inject(REQUEST) private request: any,
   private transferState: TransferState,
   @Optional() @Inject('API_KEY') private apiKey
 ) { }
 public setRedirectUrl(url: string) {
   this.redirectUrl = url;
 }
 public auth(login: string, password: string, remember: boolean): Observable<any> {
   return this.http.post<any>(`/auth/login`, {login: login, password: password}).pipe(
     flatMap(response => this.secondFactor(response.token, remember) )
   );
 }
 public secondFactor(token: string, remember: boolean): Observable<any> {
   return timer(1000, 1000).pipe(
     take(5 * 60),
     concatMap(() => this.pollStatus(token, remember)),
     filter(response => response.status !== 'pending'),
     map(response => {
       if (response.status === 'approved') {
         this.redirectUrl = this.redirectUrl == null ? '/' : this.redirectUrl;
         this.router.navigate([this.redirectUrl]);
         return true;
       } else if (response.status === 'denied') {
         return false;
       }
     }),
     takeWhile(status => !status)
   );
 }
 public getRememberedToken(): Observable<string> {
   const key: StateKey<string> = makeStateKey<string>('authyToken');
   return Observable.create(subject => {
     if (isPlatformServer(this.platformId) && this.request.cookies.remember) {
       this.http.post<any>(
         `https://api.authy.com/onetouch/json/users/${this.request.cookies.remember}/approval_requests?api_key=${this.apiKey}`,
         {message: 'Log into your Angular and Authy application'}
         ).subscribe(resp => {
           this.transferState.set(key, resp.approval_request.uuid);
           subject.next(null);
           subject.complete();
       });
     } else {
       subject.next(this.transferState.get(key, null));
       subject.complete();
     }
   });
 }
 public isAuthenticated(): Observable<boolean> {
   if (isPlatformServer(this.platformId)) {
     return of(this.request.cookies.authentication === 'super-encrypted-value-indicating-that-user-is-authenticated!');
   }
   return this.http.get<any>('/auth/isLogged').pipe(map(response => response.authenticated));
 }
 private pollStatus(token: string, remember: boolean):Observable<any> {
   const httpOptions = {
     headers: new HttpHeaders({
       'Token': token,
       'Remember': '' + remember
     })
   };
   const url = `auth/status?timestamp=${Date.now()}`;
   return this.http.get<any>(url, httpOptions);
 }
}

The new code above added the pollStatus() method and refactored secondFactor() method.

Examine the secondFactor method line-by-line:

auth-service.ts

public secondFactor(token: string, remember: boolean): Observable<any> {
   return timer(1000, 1000).pipe(
     take(5 * 60),
     concatMap(() => this.pollStatus(token, remember)),
     filter(response => response.status != 'pending'),
     map(response => {
       if (response.status === 'approved') {
         this.redirectUrl = this.redirectUrl == null ? '/' : this.redirectUrl;
         this.router.navigate([this.redirectUrl]);
         return true;
       } else if (response.status === 'denied') {
         return false;
       }
     }),
     takeWhile(status => !status)
   );
 }

The method returns an observable.

The observable is initialized with the timer() method: it will emit a value every second for up to 5 minutes The 5-minute limit is set by take(5 * 60).

The concatMap() changes the return value of the observable to the pollStatus() method output.

The pollStatus() output is filtered to remove the pending status.

The map() operator returns a boolean based on the status of authentication.

The process continues through a takeWhile() loop while the value of status is not true (approved) or until the iteration times-out.

And that completes the code for the application. The application flow can be seen in the following diagram:

Test the completed application

You should be able to see the complete functionality of the application if you have applied all the code changes successfully.

Build and run the application by executing the following npm commands in the angular-authy-remember directory:

npm run build:prod
npm run server

Open a new browser tab and open the browser’s developer tools (F12). Select the Network tab in the developer tools.

Go to http://localhost:8080. Enter the login credentials you used previously and check the Remember me checkbox. Click the Login button.

You will see “Waiting for second factor” on the /login page and you should begin to see status events in the Network tab.

When you receive the Authy authentication request on your device, accept it. You’ll see the status events end, followed by an islogged event, and the application will redirect you to the /home route, where you will see the “protected-page works!” message.

Refresh the browser tab. Because you have previously logged in successfully, the authentication cookie has been set, so the /login page will immediately begin displaying “Waiting for second factor” and the Network tab will begin displaying status messages.

You do not need to enter the User ID or Password, you do not need to to check the Remember me checkbox, and you do not need to click the Login button.

You should have also received an authentication request from the Authy app on your device. Approve it to complete the login sequence.

Just like that, you have logged into the application with a single tap! The login process is secure because it will only work if you are logging in on the device from which you have previously logged in successfully and authenticated yourself with the Authy app on your device.

If you want to catch up to this step, or compare your work to the code in the project repo, follow these steps:

Execute the following command line instructions in the directory where you would like to create the project:

git clone https://github.com/maciejtreder/angular-authy-remember.git
cd angular-authy-remember
git checkout step2
npm install

Add your Authy Production API Key and user Authy ID in the server.ts file, as described above.

Execute the following npm command line instructions in the angular-authy-remember directory:

npm run build:prod
npm run server

Perform the steps in the Test the completed application section.

Summary of expedited two-factor authentication with Angular and Twilio Authy

In this post you learned how to add “remember me” functionality to an Angular Universal + Node.js application. You also learned how to use the Angular TransferState object and a security cookie to identify returning users. You made it possible for returning users to log into an application with one tap on the Authy app, bypassing the step of re-entering their credentials while maintaining the added security of two-factor authentication. Cool beans!

Additional resources

@angular/router API documentation, including the Resolve interface.

Authy API for the complete API documentation for Twilio Authy.

jwt.io to learn more about the JSON Web Token and its capacity to carry data in a standard format and add additional security to web apps.

Node vs Angular : Comparing Two Strong JavaScript Technologies

Just from being a simple client-side scripting language, JavaScript has evolved over the years to turn out to be a powerful programming language. Here Node.js is a cross-platform runtime environment while AngularJS is one of the top JavaScript framework. Angular helps the developers to build web applications which are dynamic in nature using HTML template language and following the MVC design pattern.

15 Common Mistakes Developers Made While writing JavaScript Apps

15 Common Mistakes Developers Made While writing JavaScript Apps

Every developer make mistake some time when writing apps. This is a normal part of the development process. In this post, we'll learn 15 Common Mistakes Developers Made While Writing JavaScript Apps hope this post will help you

Common Mistakes Developers Made While Writing JavaScript Apps

Every developer make mistake some time when writing apps. This is a normal part of the development process. There are some mistakes that are made more often than others. It is good to be aware of them so that they can be corrected before it’s made. Once we can do that then we can develop apps a lot easier and become a proficient JavaScript developer since we can develop apps that makes less bugs. We will go through some of the more common bugs that are made so we can avoid them here

1. Confusing the Equals

In JavaScript, single equal, double equal, and tripe equal all have their own meanings. Single equal sign is the assignment operator which assigns the value on the left to the variable to the right. Double equal sign is the equality check operator which checks an object’s content for equality without checking its type. The triple equals operator checks an object’s content and the type for equality.

We use the single equal assignment operator like the following:

let a = 1

This is used for setting variable values, so it’s we use single equal in a place that shouldn’t be used like in:

if (a = 1){ ... }

then we would be assigning 1 to a which is always true . This means that the code inside the if statement always runs. That’s definitely not what we want.

Double equal sign shouldn’t be too too much since it doesn’t check the type of the object when checking for equality, so something like:

1 == '1'

if true . This creates problems because if we are only checking for number 1 and we get string with 1 in it, it’s still true. We want to convert them to the same type and then compare them with === to check for equality to avoid ambiguity. So if we want to compare if all forms of 1 are equal to each other we convert them to number first by using:

Number(1) === Number('1')

1 wouldn’t be equal to '1' is we use === since they are different types. This would make things a lot more clear. If we want to make sure something aren’t equal to each other then we can use !== to check if they don’t have the same content or the same type, so:

1 !== '1'

would be true .

2. Mismatching Brackets

Nested statements and functions in each other means that there’re multiple levels of brackets in each file. Usually, apps are pretty complex so the levels can add up. This means that mismatching brackets is easy if you use a text editor that doesn’t support syntax highlight or check for mismatched brackets. This can easily be avoided with modern text editors such as Visual Studio Code, Atom, and Sublime. If we want to use simpler text editors, then use linters and code formatting tools like ESLint and Prettier to detect these issues. They also let us format code automatically and detect common style issues that may occur like quote style inconsistencies, number of characters in a line, functions that can be shortened, etc.

3. Mismatching Quotes

JavaScript lets us use single quotes, double quotes, and backticks for strings. They are equivalent. However, we should open and close with the same character. So if we open a string with single quote then use single quote to close a string, and if we started with double quotes or backticks, then use those to close the string respectively. Also, special characters like quotation marks have to escape to be included in a string in some cases. If you open a string with single quotes, then if you use single quotes in a string, then you have to escape that to include it in the string. This also applies to double quotes and backticks. If you use double quotes in a double quoted string then you have to escape it. And if you use a backtick in a template string, then you have to escape the backtick character.

4. Parentheses

In if statements, parentheses always have to wrap around the whole condition. For example, something like:

if (x > y) && (y < 10) {...}

won’t work. The correct way to write that statement is to write is:

if ((x > y) && (y < 10)) {...}

if we want to check that both conditions are true.

5. Semicolon

Semicolons are optional at the end of a JavaScript line. However, to make things clear for other people, we should include it so that people know where a line ends. We can use a code linter or formatter like ESLint or Prettier to do this automatically. Lots of text editors also have add-ons to fix it automatically for you.

6. Capitalization

JavaScript code is case-sensitive, so things that have different capitalization will be considered different even if they have the same spelling. Anything that references them also have to be capitalized correctly. For example, getElementsByTagName should always be spelled this way with exact same capitalization. The general convention in JavaScript is that we spell variables and function names with camel case, so we should stick with that for consistency if we define our own variables.

7. Referencing Code That’s not Yet Loaded

It’s important that we reference code that have been defined and loaded before hand in order to use the code. If we are using script tag then before we reference the code, we have to load the code first. So the script tag that references the script with the variable we want to use should come before the script tag that references the script that has the code that we want to reference.

Fortunately, JavaScript modules are much more common nowadays, so that we just have to remember to export the code that you want to use in another module and the import the exported variable in the module that you want to use the variable before referencing it. JavaScript modules solves a lot problems with script tags. Global variables do not have to used much anymore to let different scripts reference the same variable, and also we can make variables private without the use of closures since we only need to export the ones that are needed elsewhere.

8. Variable Names

In JavaScript, there are many reserved words that cannot be used as variable names. They shouldn’t be used as variable names since they collide the name of the reserved words, creating confusion with the JavaScript interpreter. To avoid this we should use names that are descriptive like firstName , lastName , and things like that.

9. Scope

We shouldn’t use global variables whenever possible. This means that all variables we declare should use the let or const keywords for variables and constants respectively. This avoids issues with global variable scope and overwriting global variable data. It also let us avoid errors from assigning to entities that should be constant or assigning things accidentally that are global.

10. Missing or Unexpected Parameters

When functions are called with expected parameters missing, then unexpected results may be returned because you passed in unexpected input to a function.We have to make sure that we pass in the right parameters to a function so that we get the right results. It also a good idea to check for unexpected parameters if the function is used in lots of places like functions that are in libraries so that we can deal with unexpected parameters gracefully like ending the execution of the function when parameters passed in are of an invalid type or null or undefined .

11. Index Errors

JavaScript arrays starts with index 0, so the last index of an array will always be 1 less than the length of the array. When you pass in an index that is beyond the length or it’s invalid like a negative number, we get undefined , so we will get ReferenceErrors if we try to get the invalid entry and do stuff with it.

12. Null and Undefined

null and undefined are things that are often the values of variables. This means that we have to check for these when we are getting something by traversing the nested properties of objects or looping through an array. When we have null or undefined we want to handle them gracefully. This means that we should always check for them. So we if have an object called foo and we want to access deeply nested properties within it, then we should check for null or undefined in each level, like so:

if (foo && foo.bar && foo.bar.baz){ ... }

This way we know that all the properties are defined so that we can get access the baz property. For arrays if we want to access index i , we should check if it’s defined by writing:

if (arr[i]){...}

so that we won’t get unexpected undefined errors.

The optional chaining operator (?. ) is being worked on, so hopefully it will be finalized soon and we can use it to access deeply nested properties in an object and we don’t have to deal with properties being undefined as much anymore. Also, Lodash has a get function, which can try to access deeply properties of arrays and objects and get the value if it exists or return null if there’s anything undefined in the middle of the object’s hierarchy. This is much better than a long chain of undefined or null checks.

13. Confusing Undefined and Null

JavaScript has both undefined and null for non-values. However, there are quite a few differences between the two. undefined means that the variable may have been declared, but nothing is set to it. A variable can also be explicitly set as undefined . The type of an undefined variable, when checking the type with the typeof operator, will get us the type 'undefined'. Functions that don’t return anything returns undefined. On the other hand, null values have to be explicitly set by functions that return null or just set directly to a variable. When we check an object that has the null value set, we’ll find that the type of it is'object' if a variable has the null value.

For this reason, it’s probably easier to stick to undefined whenever we can when we’re setting variable values to non-values. It reduces confusion and we only have to check that the type of a variable is 'undefined' to see whether it’s undefined. That’s less painful than having two checks, for both null and undefined.

To write functions that return undefined, we don’t have to do anything like the following example:

const f = () => {}

To set a variable that was assigned some other value to undefined, we can write:

x = undefined;

To check if a property value is undefine, we can write:

typeof obj.prop === 'undefined'

or

obj.prop === undefined

To check if a variable is undefined, we can write the following code:

typeof x === 'undefined'

A declared variable that hasn’t been assigned anything automatically has the value undefined.

If we have to check for null, then we can write:

obj.prop === null

or

x === null

for variables. We can’t use the typeof operator for checking null because the data type of null is 'object'.

14. Confusing Addition and Concatenation

In JavaScript, the + operator is used for both adding two numbers and concatenating strings together. Because JavaScript is a dynamic language, the operands are all automatically converted to the same type before the operation is applied. For example, if we have:

let x = 1 + 1;

then we get two because they’re both numbers. The + operation was used for addition like we expected. However, if we have the following expression:

let x = 1 + '1';

then we get '11' because the first operand was coerced into a string before the + operation is applied. The + operation was used for concatenation instead of addition. When we use the + operator on multiple variables, this makes knowing the type even harder. For example, if we have:

let x = 1;
let y = 2;
let z = x + y;

as we expect, we get three because x and y are both numbers. On the other hand, if we have:

let x = 1;
let y = '2';
let z = x + y;

then we get '12' because y is a string, so the + operator was used for concatenation instead. To solve this issue, we should convert all the operands to numbers first before using them with the + operator. For example, we should rewrite the above example into the following:

let x = 1;
let y = '2';
let z = Number(x) + Number(y);

The code above will get us 3 as the value of z since we converted them both to numbers with the Number factory function first. The Number function takes in any object and returns a number if it can be parsed into a number, or NaN otherwise. An alternative way to do this is to use the new Number(...).valueOf() function, as we do in the following code:

let x = 1;
let y = '2';
let z = new Number(x).valueOf() + new Number(y).valueOf();

Since new Number(...) is a constructor that creates an object type, we want to use the valueOf function to convert it back to a primitive type to make sure that what we get is a number type. A shorter way to do this is to write:

let x = 1;
let y = '2';
let z = +x + +y;

The + sign in front of a single operand will try to convert the single operand into a number or toNaN if it can’t be converted into a number. It does the same thing as the Number function. We can also convert a variable to a particular type of number. The Number object has a parseInt function to convert an object into an integer and a parseFloat function to convert an object into a floating-point number. parseInt takes the object you want to convert to a number as the first argument. It also takes a radix as an optional second argument, which is the base of the mathematical numeral systems. If the string starts with 0x, then the radix will be set to 16. If the string starts with anything else, then the radix will be set to 10.

We can use them as in the following examples:

let x = 1;
let y = '2';
let z = Number.parseInt(x) + Number.parseInt(y)

Also, we can use the parseFloat function as in the following code:

let x = 1;
let y = '2';
let z = Number.parseFloat(x) + Number.parseFloat(y)

We will get 3 in both of the examples above.

15. Breaking Return Statements Into Multiple Lines

JavaScript closes a statement at the end, so one line code is considered distinct from the other. For example, if we have:

const add = (a, b) => {
  return
  a + b;
}

we get undefined if we run console.log(add(1, 2)); since we ran the return statement, which ended the function execution, before a + b is run. Therefore, a + b will never be run in this function. To fix this, we either have to put the return statement all in one line or use parentheses to surround what we want to return. For example, we can write:

const add = (a, b) => {
  return a + b;
}

This will log 3 if we run console.log(add(1, 2)); since we are actually returning the computed result in the function. We can also write:

const add = (a, b) => {
  return (
    a + b
  );
}

This is handy for returning expressions that might be longer than one line. This will also log 3 if we run console.log(add(1, 2));. For arrow functions, we can also write:

const add = (a, b) => a + b

for single-line functions since the return statement is implicit for single-line arrow functions. We can also write:

const add = (a, b) => (a + b)

to get the same thing. This also works for single-line arrow functions.

In JavaScript, if a statement is incomplete, like the first line of:

const power = (a) => {
  const
    power = 10;
  return a ** 10;
}

inside the function then the JavaScript interpreter will run the first line together with the second line to get the full statement. So:

const
  power = 10;

is the same as:

const power = 10;

However, for complete statements like return statements, the JavaScript interpreter will treat them as separate lines. So:

return 
  a ** 10;

is not the same as:

return a ** 10;

Even though JavaScript is a friendly language, it’s still very easy to make mistakes when writing JavaScript code. It’s easy to confuse undefined and null when we aren’t familiar with JavaScript. Because of the dynamic typing nature of JavaScript, operators like the + operator that can do multiple things can easily be converted to a type we don’t expect and produce the wrong result. Also, if statements can be complete on their own, then they shouldn’t be written in their own lines if we want both lines to be together.

Yes, that is all. I hope this tutorial will surely help and you if you liked this tutorial, please consider sharing it with others. Thank you !

An Angular Roadmap — The Past, Present, and Future of Angular

An Angular Roadmap — The Past, Present, and Future of Angular

✅Interested in being an Angular developer in 2019? ... blog post it's most likely that you've written some code in javaScript in the past.

Paleolithic JavaScript — SproutCore

In the beginning, there was SproutCore. It was the first comprehensive JavaScript framework aimed at making it easy to build desktop-quality single-page web apps. It’s not that this wasn’t possible before. When Google released Gmail, it showed the world that web apps really could replace complex desktop applications. Google even open-sourced the Closure toolkit — a set of libraries and an optimizing compiler that it used to build Gmail.

The problem was that Google’s Closure tools weren’t very developer-friendly. They relied heavily on Java, which alienated web developers who were used to working with JavaScript, PHP, Ruby, and Python. Gmail was a great demonstration of what was possible, but developing similar applications still felt out of reach for many.

Some courageous developers managed to string together amazing single page apps using a combination of jQuery, duct tape, and hope. While these apps looked amazing to end-users, for the developers working on them, the apps quickly turned into hulking piles of technical debt that made the dev team dread heading to work in the morning.

As a result, a few enterprising developers began to work on frameworks that would bring Gmail-like apps within easy reach of web developers everywhere. SproutCore was the first of these frameworks to take off. It came with a complete set of widgets that made it possible to build complex web applications without even touching HTML or CSS.

This ended up being great for former desktop developers who had been dragged kicking and screaming onto the web. Several more frameworks popped up with similar goals; GWT and Cappuccino were the most prominent. These frameworks even avoided JavaScript by transpiling other languages into JS. Again, this was great for desktop developers. But it left passionate web developers out in the cold and made them feel as though their hard-won HTML, CSS, and JavaScript skills weren’t valuable.

This left an opening for a framework that truly embraced the web, instead of trying to plaster over it and pretend it was something else. A couple of early frameworks (Backbone and Knockout) appeared, and achieved a moderate amount of success. Ember also showed up around this time. It took SproutCore, stripped it down to its bones, and tried to rebuild it into something truly web-friendly. Ember wanted to be the Six Million Dollar Man of the JavaScript world: rebuilt better, stronger, and faster.

None of these frameworks rocketed to popularity. The world was waiting for something better. In 2010, that something better appeared — it was named Angular.

The Golden Age of Angular

Even before Angular version 1.0 had been released, Angular took the front-end development world by storm. Finally, we had an easy-to-use JavaScript framework that treated HTML as a first-class citizen. Developers and designers could now work together to build amazing single-page applications. This came as a relief to designers, who had been annoyed and offended because older frameworks had treated HTML and CSS as tools for barbarians, tools that no civilized developer should have to touch.

The first thing that seemed magical to developers trying Angular for the first time was two-way data binding. Prior to this, most developers had only seen this kind of data binding in desktop frameworks like WPF and Windows Forms. It was great to be able to bind forms and other UI elements to JavaScript model objects. While two-way data binding could cause performance problems when overused, teams that used it judiciously found that Angular enabled them to create complex front-end applications much more quickly than ever before.

Angular proved to be popular for more than just easy binding of data to HTML elements. Angular directives provided an easy way to create reusable HTML + CSS components. Although other JavaScript frameworks provided this before Angular, Angular was the first one that became extremely popular. Reusable components had long been in-use in server-side frameworks. ASP.NET user controls and partial templates in Rails and Django are but a few examples.

Finally, Angular made dependency injection popular in the front-end development world. Dependency injection had long been popular in enterprise applications, which is perhaps why it hadn’t caught on in the JavaScript world. Front-end developers have long been averse to what they see as needlessly complex enterprise software design patterns. This concern isn’t without merit. Have you ever, in the course of writing an application, said to yourself “What I really need here is a “SimpleBeanFactoryAwareAspectInstanceFactory?”

Dependency injection, though, has proven its worth. And Angular made dependency injection easy to use for an audience that hadn’t used it much in the past. Need an HTTP client? Or perhaps you’d like to do some animation? No problem. Angular had built-in services for those. Just ask for them, and Angular would inject them into your components. No need to instantiate anything yourself.

Or perhaps you wanted to use the browser’s window or location objects without making it impossible to unit test your components outside of a browser? Angular had you covered there too, with its built-in $window and $location services. At runtime, you’d get the browser objects you were expecting. And when running unit tests server-side in Node.js, you could pass mock services into your components to ensure they behaved as expected in various scenarios.

If all of this wasn’t enough, Angular also made it simple to register and inject your own services. For developers who were used to binding all their data to the DOM and hoping for the best, this was awesome. If you were writing a new front-end app that called for APIs that would cost your company a lot of money if overused, you’d probably prefer to be able to write tests ahead of time to ensure that your application doesn’t try to do something like calling the Twilio API 800 million times.

So you’d create a Twilio service that gets injected at runtime. At testing time, you’d create a mock service that records the cost of every API call your application is trying to make. You’d write tests that cover common usage scenarios and ensure that these scenarios don’t result in your company receiving a 7-figure bill. Overall, most developers found that Angular directives combined with dependency injection made it possible to write modular, testable front-end applications using tried-and-true software engineering techniques. Many development teams decided that this resulted in a happy state of affairs, and decided to go all-in on Angular.

The Angular Decline? The Rise of React

While things were mostly great in the world of Angular, it wasn’t all sunshine and lollipops. Developers were starting to run into severe performance problems when they tried to bind too many model objects to too many DOM elements. Some applications slowed to a crawl. Direct calls to $digest and other black-magic sorcery started becoming necessary to achieve acceptable performance. Around the same time, a new challenger appeared: React. At first, React didn’t seem to pose too large a danger to Angular. After all, these React weirdos had gone to the trouble of inventing JSX, which looked a lot like a way to mix markup into your code. Hadn’t we gone to a lot of trouble to invent templating languages for the explicit reason of avoiding mixing markup and code?

As it turned out, React’s approach was pretty popular in the front-end development community. It didn’t rocket to popularity, however. Angular was still dominant, and it looked like it would remain that way. Until that is, Angular’s popularity was given a good kick in the teeth from an unexpected source: the Angular team itself.

The Introduction of Angular 2

Angular 2 was first announced at the ng-europe conference in 2014. The Angular team’s plans came as a shock to the Angular community, to say the least. Reaction from Angular developers was swift and negative… and not without reason. Angular 2 would be getting rid of many familiar concepts from Angular 1, introducing a new, incompatible templating language (and oh, by the way) would also be programmed using an entirely new language.

AngularJS

Although both Angular 1 and Angular 2 were called ‘Angular,’ in reality, they were very different frameworks with a few things in common. To help prevent confusion, the Angular team started referring to the old version of Angular as ‘AngularJS’, and the new version as simply ‘Angular.’ This makes intuitive sense since AngularJS was written in JavaScript, and Angular was not. To keep the distinction between the frameworks clear, I’ll be referring to Angular 1 as AngularJS from this point forward.

As a result of all of this, AngularJS developers lost faith in the framework’s future. They threatened to move to a new framework on future projects, and that is precisely what many of them did. React was the biggest beneficiary of the mass exodus from AngularJS.

Although React didn’t do as much as AngularJS, in a way that was positive. If you’re using a view library that doesn’t try to include everything plus the kitchen sink, it’s a lot more difficult for the developers of that library to pull the rug out from under you in the future. In the beginning, using React was a bit of a pain compared to AngularJS. You had to cobble together a patchwork of libraries just to cover the functionality the AngularJS provided out of the box.

Many teams saw this as a good way to reduce risk, because it was unlikely that the developers of all of those libraries would decide to make backward incompatible breaking changes at the same time, which is essentially what Angular had done.

The Emergence of Vue

To compound AngularJS’ woes, another framework named Vue showed up at about the same time the drama over Angular 2 was occurring. Vue was inspired by AngularJS but aimed to simplify it and get rid of what Vue’s creator saw as unnecessary complexity (so Vue felt very familiar to existing AngularJS developers). Vue provided a safe haven for many AngularJS developers who didn’t want to move over to React.

This doesn’t mean that AngularJS developers were not waiting patiently for Angular 2 to appear. But it’s clear that there was a mass exodus from AngularJS to React and Vue due to the uncertainty caused by the plans for Angular 2.

Rising From the Ashes with Angular 2

Eventually, Angular 2 was released. As expected, it did away with many familiar concepts from AngularJS but kept a few of the best pieces like services and dependency injection. Fortunately for the sanity of developers, Angular uses plain TypeScript and not a fork as originally planned.

To make things more confusing, the Angular team maintained a fork of the new framework that used the Dart programming language instead of TypeScript. Initially, the TypeScript and Dart versions were developed in sync, generated from a single code base. Eventually, the TS and Dart versions of Angular decided to go their separate ways, and Angular Dart now exists on its own.

Even with this confusion, Angular’s popularity began to increase again after the Angular 2 release. It happened slowly. As often occurs in software development, trends shifted. Developers realized that a big, batteries-included framework might actually be useful. After all, when your application grows large enough, you end up actually needing all of those batteries.

Enterprise developers, in particular, began moving back to Angular. This makes sense. Usually, when you start an enterprise web app, you know it is going to be complex. There’s no point in starting with a tiny MVP when you know from the beginning all 87 things your application is going to be expected to do.

Where’s Angular 3?

Although Angular 2 wasn’t perfect, many developers of complex web applications began to realize that the new-and-improved Angular was a good fit for their needs. Fortunately for them, Angular had some exciting improvements in store. More importantly, the Angular team demonstrated that it could consistently publish new versions of the framework with few breaking changes between versions

In a move that seemed odd at the time, the Angular team decided to skip version 3 entirely and move to version 4. This was done for good reason: the team working on Angular’s router package had already pushed ahead and released version 3, while the remainder of Angular was still at version 2.3. They decided to keep all Angular package versions in sync moving forward, and bumping everything up to version 4 for the next release was the easiest way to achieve this.

Angular 4

Angular 4 had some significant changes, including added ahead of time compilation, which resulted in small production JavaScript bundles and shorter application load time. Support for server-side rendering was added, which was a boost for teams that wanted to render their app ahead of time to improve initial load performance. Many other improvements were added throughout the framework, but upgrading apps from Angular 2 to 4 was quick and painless in most cases.

Angular 4.3 and Angular 5

Angular 4.3 added a new HTTP client that was easier to use than the old HTTP service. In Angular 5, the old HTTP service was deprecated and would be dropped in the next release. In spite of this inconvenience, there was relatively little grumbling because the upgrade in most cases was straightforward. Angular 5 also added better internationalization support and further build optimizations.

Angular 6 and 7

Angular 6 and 7 were disappointing to some developers. There were no large changes, but there were many small quality of life improvements, especially to the Angular CLI tooling. The decreasing number of visible changes isn’t an indication that the Angular team has stopped innovating. Instead, it shows that the framework is mature, so the development team is now free to do more work behind the scenes, fixing bugs and improving performance.

The stability of the framework since the release of Angular 2 has drawn some old-school AngularJS developers back into the Angular world. It has also attracted the attention of enterprise development teams. When you’re building enterprise apps that may live for decades it’s ideal to use a framework that gets new releases on a predictable schedule but doesn’t change too rapidly. A developer who had only used Angular 2 could be up and running and contributing to an Angular 7 app within minutes.

The Future of Angular

Angular 8 and Angular Ivy

And that brings us to today. As we’ve seen, Angular has come a long way. It has gone from loved by web developers to being reviled to being admired, although it isn’t yet loved again like it was in its early days.

On the horizon, we have Angular 8. A ton of work has been done in Angular 8 to make it easy to use with the Bazel build system, which is absolutely amazing news for all 3 developers who are using it outside of Google. More excitingly, though, the Angular team is hard at work on a new rendered called Angular Ivy. It’s intended to be a drop-in replacement for the current rendered. For the most part, current apps won’t need to make any changes to use Angular Ivy.

If Angular Ivy is a drop-in replacement, why should developers care? Two important reasons: speed, and bundle size — two very important concerns. For a few years, it seemed like web developers had gone a bit crazy. Teams were shipping JavaScript bundles that were 5MB, 10MB, or even larger, and thinking that there was no problem with this. After all, the applications worked perfectly on the developers’ i7-powered MacBook Pros so they should work fine for everyone, right?

Unfortunately, in the real world, not everyone is running the latest and greatest hardware. Hundreds of millions of people access the internet solely on older Android phones with slightly more processing power than a potato, through internet connections only a little faster than dial-up. For these users, a huge JavaScript bundle takes forever to load, and even longer for their device to parse and run. Even in less extreme cases, there are countless users around the world who aren’t using the latest and greatest hardware. For them, massive JavaScript apps are usable (but painful).

Angular Ivy Expectations

The Angular Ivy renderer will help in several ways:

  1. It is being written with an eye on efficiency, so it will accomplish the same tasks while executing far fewer CPU instructions. This will improve both the battery life and the sanity of users with less-than-powerful devices.
  2. The renderer will be written in a much more modular fashion that the current renderer. This will make it much more amenable to tree-shaking and dead code elimination. As a result, your production JavaScript bundle will include only the code that is needed to run your application, instead of bundling together everything plus the kitchen sink as often happens with the current rendered.
  3. In addition to the bundle-size reduction and improved rendering speed, Angular Ivy has another few quality-of-life enhancements for Angular developers. Rebuild times are significantly faster. So if you’re running your app in development mode and waiting for your changes to appear, you’re now going to be spending a lot less time waiting.
  4. Template-type checking is improved, which means you’ll catch more errors at compile time instead of at runtime. Runtime template bugs are annoying, because they either bite you during testing, or they bite your users when they’re trying to use your app.
  5. The Angular Ivy template compiler will generate code that is human readable, which the current View Engine compiler doesn’t do. This will come in handy when trying to track down tough template bugs.

The net result: smaller apps, faster apps, happier developers, and happier users.

Angular’s Past, Present, and Future

If you’ve been using Angular from its early days all the way until now, then congratulations! While there have been plenty of rough patches, we’ve ended up with a fast, modern framework that is fun to use.

If you were an AngularJS developer but moved on to React, Vue, or something else, I encourage you to give Angular another look. It’s worth your time, even if you decide to stick with what you’re using now.

And if you’ve never used Angular at all, why not give it a shot?

We’ve just been on a whirlwind tour through Angular’s past, present, and future. Without a doubt, it has been quite a ride. Regardless of your Angular background, I hope you’ve enjoyed the tour!

30s ad

Angular 2 Firebase - Build a Web App with Typescript

Angular 2 Demystified

Master Angular 2 - The No Nonsense Course

Complete Angular 7 - Ultimate Guide - with Real World App

A Quick Guide to Angular 7 in 4 Hours