Oct 28, 2018

Angular - Best Practices

Using Immutability

Generally speaking, immutability is a good practice in JavaScript whether we are using Angular or not, so the recommendation to prefer immutability is a good recommendation in all JavaScript code. In general, do not mutate existing objects in memory, but rather create new objects. Using immutability can help you avoid certain classes of bugs, such as bugs that occur when a value is unexpectedly changed from somewhere else in the code. Using immutability can also help with certain types of change detection in Angular. Refer following for safe way of deep copying an object.
function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(obj[i] != null &&  typeof(obj[i])=="object")
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}
let newObj = JSON.parse(JSON.stringify(obj));

copy via object assign

Following will do shallow copy, left most is target. value in right will override argument in left.
Object.assign({},employee,{name:'New Name'}, {age:10})

copy via spread

const copyObject = {...objtobecloned, {name:'New Name'}}
const copyArray = [...arrayToBeCopied, ]

map, filter, reduce, concat, spread mutate the array where as push, pop, reverse are immutable.

You can also use library like Immer.

Callback hell

When writing callback keep an eye on a number of curly braces as it gets difficult to manage if you have deeply nested callback. It's sometimes neat to put callback (if it's getting bigger) in a separate function.

Prefixing Component Selectors

Prefixing your component selectors will avoid conflicts if you happen to import a module that has a component selector that conflicts with one of your own.

Delegating Complex Logic to Services

Inside component, you mostly initialize form controls, add validators, redirect logic, event handler, etc, any business logic or complex processing should be in service. On the other hand, service should not have to deal with form controls objects.

Code Organization

Properties at the top followed by the constructor, followed by interface implementation, followed by the component public method and at the end private method. Implement Life Cycle Hook Interfaces like OnInit, OnChange.

Service Injector Best Practices


For every Angular app, Angular creates a root injector, which is responsible for injecting services wherever they're needed. If you provide a service in the eagerly loaded module, then angular register that with the root injector which makes it (singleton) available to the entire application. On the other hand, if you provide a service in a lazily-loaded feature module, Angular creates a new injector for that module and registers it there. So the instance of the service is only available to that lazily-loaded feature module. This behavior of creating a second instance is unique to lazily-loaded feature modules. Just remember that if you provide a service in a lazily-loaded module, it is only available to that module, and if you need a single instance of a service to be available everywhere, define it in your core module.

Ahead-of-time Compilation and tree shaking CLI

Use cli to build

Lazy Loading Feature Modules

Modules are not downloaded at the launch of the application rather only eagerly loaded module is downloaded. There are three type -
 Lazy Loading - Module is downloaded only when the user navigates to lazily loaded feature.
 Preloading - At the launch of application only eagerly loaded module is downloaded and hence user is severed quickly. Once downloaded and template appears, router checks for preloaded module and download them. This way
 application launch becomes fast as at that time user is downloading only eagerly loaded module and once user is served, angular downloads feature module, so its available for user when user try's to navigate to it.
 Custome Preloading - You can put custom rule to defined preloading behavior.

Monitoring Bundle Sizes


It's very important to keep an eye on the bundle size of all the chunks which gets created during build. You can use source-map-explorer to peek into your bundle to see whats taking most of the space. Ultimately user will be downloading these bundles and smaller the bundle size faster it would be to download
 ng build --prod --source-map

Improving Performance with OnPush Change Detection

Application state change can be caused by three things - Events (click, submit, ), XHR (http call), Timer (setTimeout, setInterval). These are the asynchronous operations which triggers change detection. So when change detection is triggered each of bindings will be evaluated, which can cause performance concern on a page which has lots of binding. So if you don't expect any of your binding to get impacted then you may add OnPush so that bindings are not re-evaluated on events, xhr or timer. To test add following <div>{{callMethod()}}</div> to your template and you will notice that callMethod will be called everytime an event is fired on the component or http call happens.

Pure and Impure Pipe Performance

A pure pipe is only called when Angular detects a change in the value or the parameters passed to a pipe. An impure pipe is called for every change detection cycle no matter whether the value or parameters changes. So in case of pure pipe, when you pass an array and one of the element of array changes, the pure pipe will not be called as the instance remain the same. So if you have sort custom pipe (pure) which takes an array, the pipe will not be executed if you update one of the element of the array

Oct 12, 2018

Angular - Router Guard

Angular router provides several types of guards. Guard is an angular injectable service which you register as a provider and use it when you configure a route. You also have an option to create it just like a function, but typically in production code, you will have a service. Following is the order in which guards are executed and if any guard returns false, all pending guards are canceled, and the requested navigation is canceled.
  • canDeactivate - The router first executes the canDeactivate guards for the current route to determine whether the user can leave that route.
  • canLoad - If a feature module is loaded asynchronously, the canLoad route guard is checked before the module is loaded; it won't even be downloaded unless the guard requirements are met. Unlike the canActivate, the canLoad method cannot access the ActivatedRouteSnapshot or RouterStateSnapshot because the module defining the route is not yet loaded.
  • canActivateChild - This is to guard activation to a child route to protect child route
  • canActivate - Guard to protect the route.
  • resolve - After all other route guards are checked, the resolvers are executed, so you resolve only when you have access to the route. This is typically used to fetches data before the component is activated. This way component doesn't have to show partial data or put special logic to work around that while data is being downloaded from the server.

The router extracts any route parameters from the URL and supplies them to the component through its ActivatedRoute service. It provides access to URL segments, route parameters, query parameters, route data and even access to the parent route. These are exposed as observables so you can subscribe which will notify of any parameter change. A controller onInit is only called once when a component is initialized, meaning route parameter change (navigating from app/1 to app/2 in cased of route like app/:id) will not call onInit, so to make sure you update your component based on id in the browser, you get hold of the ActivatedRoute and then subscribe to param change. On the other hand routeguard will be called every time, even when route parameter change and it will be passed with ActivatedRouteSnapshot, which has same properties as ActivatedRouty as plain values, while ActivatedRoute exposes them as observables.

Oct 5, 2018

Angular 2 - Show spinner using Router Resolvers and Event before activating route

The idea here is that we will create a route resolver and then we will subscribe to the router event and on NavigationStart event we will start the spinner and on NavigationEnd and other related events we will stop the spinner. This way new component is not activated until data is fetched to render that component, and until data is being fetched user will be displayed with the spinner.

Route resolver is a service which imports Resolve interface from ‘@angular/router’. Here you implement the resolve method which has two parameters - ActivatedRouteSnapshot and RouterStateSnapshot. This method returns observable of an object which you want to return. In your route configuration, you activate this by adding resolve. Through ActivatedRouteSnapshot, you can get hold of all route-related data for the route being activated, like parameters, query string, etc. Now at this place, you can call your service to interact with the server, before the new component is activated. This way you can handle any error which server may return as well your component is not partially displayed.

To implement spinner, in your application component (app's root component), subscribe to router event method and initialize some variable based on which you can show spinner on the page (using css you can place spinner at the center of the page)

 router.events.subscribe(
  (event: Event) => {
   if (event instanceof NavigationStart) {
     this.loading = true;
   } else if (
     event instanceof NavigationStart ||
     event instanceof NavigationEnd ||
     event instanceof NavigationCancel ||
     event instanceof NavigationError ) {
     this.loading = false;
   }
  });