Showing posts with label angular. Show all posts
Showing posts with label angular. Show all posts

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;
   }
  });

Aug 7, 2017

Angular 2 Adding http service

Angular provides @angular/http npm package to perform http request. HttpClient is available as injectable class with all the methods to perform http request. This is from HttpClientModule.

Once you have module imported you should be able to user Http class for performing  http request. In theory you can inject this (http: HttpClient ) in your component class, but to have better separation of concern you should create injectable service and let that handle http call.

As you can see from the http api documentation , it returns Observable<Response>. You should be able to use all Observable Instance Methods on this. Refer this for list of methods which can be used on  Observable. Some of the common filter, map, catch, forEach, groupBy, merge, retry, toPromose.

Since this is based on observable, the actual http call will not happen until it has any subscriber.

Refer following for a simple service which call an http endpoint.
  
import { Observable } from 'rxjs';
import { retry } from 'rxjs/operators';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class MyService {
  constructor(private http: HttpClient) { }
  public getData(): Observable {
    return this.http.get('someurl').map((data) => { return data.json() });
  }
}

Apr 11, 2017

Angular - Observables

Observables is an ES7 feature which means you need to make use of an external library to use it today. RxJS is a good one. This is not angular 2 specific feature, though angular cli does add this to the dependencies. Observables gives you all the features of promises and more. A Promise handles a single event when an async operation completes or fails, whereas Observable is like a Stream and allows to pass zero or more events where the callback is called for each event. For example FormControl valueChanges returns Observable, so I can write a code like this which will write to console every time value is changed.
   
   let sub =  this.name.valueChanges.pipe(debounceTime(1000))subscribe(
      (newValue: string) => {
       console.log(newValue);
       if (newValue.length === 5) {
        sub.unsubscribe();
       }
      });

In the following example we are making an http call and I am expecting number, then I apply pipe, which gives me option to transform data before passing to the subscriber. This will be helpful if I would like to transform data before sending to subscriber or may be convert error to standard format. Keep in mind observable are deferred execution, so unless it has a subscriber it (along with operators in pipes) will not be executed
   import { Observable, BehaviorSubject, throwError, combineLatest, forkJoin } from 'rxjs';
   import { retry, catchError, tap, map, filter, finalize,  delay,debounceTime } from 'rxjs/operators';
   import { HttpClient } from '@angular/common/http'; 

   this.http.get(url).pipe(
        retry(3),
        map(obj=>{return obj *2;}),
        tap(obj => {console.log(obj)}),
        catchError((err)=>{return throwError(err);})
      ).subscribe(
        (value)=>{console.log(value)},
        (err)=>{console.log(err)},
        ()=>{console.log('done')}
      );

combineLatest
once all input observables have produced at least one value it returns Observable and after that it returns Observable everytime it produces a new value.
forkJoin
It require all the observables to be completed and then returns single value that is an array of the last values produced by the input observables

Observable also has the advantage over Promise to be cancelable. One of the example will be for type ahead, if user has changed the text which will result in new http call, we can cancel subscription to the previous one. In case of promise, the callback call will happen either in success or failure scenario. Promises doesn't have option of Lazy loading where as observable will not be executed until someone subscribe to it. You also have option on retry and retryWhen in observable.
If you subscribe to an observable or event in JavaScript, you should unsubscribe at a certain point to release memory in the system, otherwise it will lead to memory leak. Here are few of the case where you should explicitly unsubscribe
1. Form value change as shown in the example above
2. Router to be on safe side, though angular claim to clean it up.
3. Infinite observable
 Observable.interval(1000).subscribe(console.log(''))
 Observable.fromEvent(this.element.nativeElement, 'click').subscribe(console.log('hi'));
For the following case you don't need to unsubscribe
1. aysnc pipe - When the component gets destroyed, the async pipe unsubscribes automatically.
2. Finite Observable - When you have a finite sequence, usually you don’t need to unsubscribe, for example when using the HTTP service or the timer observable

Apr 10, 2017

Angular 2 - Forms & Validation

Template Based form 
For this you need to import FormsModule. As soon as you import FormsModule, ngForm directive becomes active on all <form> tags. You can export it into a local template variable (#myForm="ngForm"). This will give access to aggregate form value (myForm.value), child controls (myForm.controls['control's name attribute']) and validity status (myForm.controls['formElement'].valid or myForm.valid) as well as user interaction properties like dirty (myForm.controls['formElement'].dirty), touched(myForm.controls['formElement'].touched) etc.
Angular provides ngSubmit ((ngSubmit)="saveMe(myForm.value)") directive which prevents form to be submitted to server
For binding you can use ngModel. If you need two way binding then use [()]. () Html to component direction, [] component to html
[(ngModel)]="somePropertyDefinedInComponent" ngModel require name attribute
In theory you should be able to use input event and then assign any of the component's property to the value of the input element. Most likely you will not do this as angular provides shot cut methods as described earlier.
(input)="somePropertyDefinedInComponent=$event.target.value"
ngModelGroup - If you want to group certain properties nested within property then you use ngModelGroup="property under which all elements will be nested"
Model based form or reactive form
In template based approach all the logic resides in html, so complex scenarios (like cross field validation etc.) may not be easy to achieve and also you cannot unit test your code. So for this case you can use reactive form for which you need to import ReactiveFormsModule. In your component you create FormGroup and add all form controls to it

   myFormGroup = new FormGroup({
      name: new FormControl('', [Validators.required, Validators.pattern('[a-zA-Z].*')]),
      address: new FormArray([
        new FormGroup({
          city: new FormControl(),
          state: new FormControl(),
        })
      ]),
      cityVisited: new FormArray([
        new FormControl()
      ])
    })

In the template, bind form formGroup attribute to the FormGroup object created in the component and input elements you need to bind it the FormControl property of component

     <form [formGroup]="myFormGroup" 
     formControlName="name" or [formControl]="myFormGroup.controls.name"
     <div *ngFor="let item of myFormGroup.controls.address.controls; let i=index">
         <input  [formControl]="item.controls.state" />
     </div>
     <div *ngFor="let item of myFormGroup.controls.cityVisited.controls; let i=index">
         <input  [formControl]="item" />
     </div>


FormGroup tracks the value and validity state of a group of FormControl instances.

Custom Validation
Create a function which takes FormControl as a parameter and returns object (property usually with the validator name and value as any value which you may want to show). If the function returns null then its valid otherwise its invalid. You can also create directive  and implements Validator. You can call updateValueAndValidity() on specific controller to trigger its validation.

Apr 6, 2017

Angular 2 Directive

Directive change appearance or behavior of the element. Component is an element and directive is attribute. It is defined similar as component, in place of @Component you use @Directive. Also notice selector is wrapped with [] which indicates its an attribute.

@Directive({
selector: "[my-directive]",
})

Within directive you can get reference of the element like this

private el: HTMLElement;
        @Input("modal-trigger") modalId: string; //you need to wrap modal-trigger in "" as it has - which is not allowed in variable name

        constructor(ref: ElementRef) {
               this.el = ref.nativeElement;
        }

Now finally you can add this directive to any of the element
<some-element my-directive="some-data-to-be-passed">

Angular 2 Routes

Setting up routing requires that we define a base path, import the Angular router, configure the routes to define which route path activates which component, identify where to place the activated component's template, and activate routes to navigate based on user actions
 
The RouterModule provides router service to manage navigation and URL manipulation, configuration for configuring routes, and directives for activating and displaying routes. Router service deals with the globally shared resource, the URL location, there can only be one active router service. To ensure that there is always only one active router service, even when importing RouterModule multiple times, RouterModule provides two methods- forRoot and forChild. RouterModule.forRoot declares the router directives, manages our route configuration, and registers the router service. We use it only once in an application and for feature route use forChild.
 

Order In which Route Path is Evaluated

The router will pick the first route with a path that matches the URL segments. It merges the application routes explicitly defined in the application module with the routes from the all feature imported module. The routes which are explicitly configured in a module are processed last after any imported modules.
 
AppModule
 imports: [
  ...
  RouterModule.forRoot([
   { path: '', redirectTo: '/home', pathMatch: 'full' },
   { path: 'home', component: HomepageComponent },
   { path: '**', component: PageNotFoundComponent }
  ]),
  UseraccountModule,
..
 ]
 
UseraccountModule
 imports: [
  CommonModule,
  RouterModule.forChild([
   { path: 'signin', component: SigninComponent },
   { path: 'signup', component: SignupComponent }
  ]),
  ...
 ],

In the above case route is evaluated like following, notice it will first evaluate routes from imported UseraccountModule and then route from AppModule.
 { path: 'signin', component: SigninComponent },
 { path: 'signup', component: SignupComponent }
 { path: '', redirectTo: '/home', pathMatch: 'full' },
 { path: 'home', component: HomepageComponent },
 { path: '**', component: PageNotFoundComponent }
 

Directives

Router outlet Directive - Directive from the router library that is used like a component. It acts as a placeholder that marks the spot in the template where the router should display the components for that outlet.
RouterLink - Directive to navigate between routes. This will not load the entire page rather route defined within router outlet directive. This is different than href as href will load entire page and will make server call. Within the component you can use Router service to navigate between routes.
RouterLinkActive - Directive let you add CSS class to an element when the links route become active.

Angular2 Service Dependency Injection

A provider provides the concrete, runtime version of a dependency value.
{ provide: Logger, useClass: Logger} is same as Logger. This tells the injector to return instance of Logger when someone ask for Logger
{ provide: Logger, useClass: BetterLogger} - This tells the injector to return instance of BetterLogger when someone ask for Logger
Now you can inject logger by using a Logger type which is dependency injection token. In the following example an instance of Logger (or BetterLogger) will be injected via private property logger. Within the class you should get proper intellisense and type safety based on type Logger
constructor(private logger: Logger){}

Its better to always use decorator @Injectable() to a service class, even though its only mandatory if your service has dependency (inject other service as dependency of its own) on some other service. Decorators simply add meta to our code when transpiled.

MyService = __decorate([
        Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Injectable"])(),
        __metadata("design:paramtypes", [_angular_common_http__WEBPACK_IMPORTED_MODULE_2__["HttpClient"]])
    ], MyService );
Here The paramtypes metadata is the one that is needed by Angular’s DI to figure out, for what type it has to return an instance.
TypeScript generates metadata when the emitDecoratorMetadata option is set and decorator is attached to the class, method etc

OpaqueToken
These are used to create non class dependency. For example for jQuery or any other third party library which do not have typescript class you can define OpaqueToken

import {OpaqueToken} from "@angular/core";
export let JQ_TOKEN = new OpaqueToken("my app jquery");

Similarly for DI on interface you can define OpaqueToken
export interface AppConfig {
 apiEndpoint: string;
 title: string;
}

export const HERO_DI_CONFIG: AppConfig = {
 apiEndpoint: 'api.heroes.com',
 title: 'Dependency Injection'
};

import { OpaqueToken } from '@angular/core';

export let APP_CONFIG = new OpaqueToken('my app config');

Now in the providers you can use it like this


{ provide: JQ_TOKEN, useValue: myAppjQuery }


Here you need to have myAppjQuery defined (let myAppjQuery: Object = window["$"];). Where ever you use JQ_TOKEN you will get handle of myAppjQuery, which at runtime will initialize as window["$"], so as long as jQuery is loaded in the rootwindow, you should be able to user it.
{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }

The above example is for interface which is not typescript class, so we defined Opaque token for that. Where ever this token will be used it will refer to value HERO_DI_CONFIG.

Now in your application, you should be able to inject this like this
constructor(@Inject(JQ_TOKEN) private $: any){}
constructor(@Inject(APP_CONFIG) config: AppConfig) {}

Mar 31, 2017

Angular 2 Components

Component consisted of two part one is component class which is like any other TS class and the other is meta data (@Component). Here you define selector, template , style etc.

Communicating with child component can be done by creating input property in child component and from parent component html pass this as attribute with square bracket

Communication with parent component

  • Template variable - Using template variable you can reference any child component output property within the template.
  • EventEmitter - Using output property of type EventEmitter, you can emit any event which you can bind in the parent component using parenthesis. In the event you can pass any data from the child component.


CSS is encapsulated within component, meaning css used in parent component will not affect child component and visa versa. You can still define global css which will be applied to all the components. 

Binding

Interpolation is used when you need to display the data {{}}. The text between braces is evaluated and then converted as string to display data. You can use javascript expression here, which do not have or promote side effects, for example  binding cannot contain assignment; {{ title='test' }} is not allowed. It can also invoke method of host component. Though inside method you can do some assignment, for which angular will not throw error but you will get unexpected result and this should be strongly avoided.

Refer following example, here we are assigning title property of host component to the value attribute of the input DOM element. This will be one way, meaning value property of component will be evaluated every time change detection cycle is triggered and string conversion of that will be assigned to the value attribute of the element
<input type="text" value="{{title}}">

Similarly in the following case div element will display title property of the component
<div>{{title}}</div>

Property binding [] is used when you want to bind data to property of dom element. For example in the following case value property of input DOM element is assigned with title property of host component. This will again be one way meaning value property will be eveluated eveytime change detection cycle is triggered
<input type="text" [value]="title" >

Event binding are used to bind event of the element. The expression used in this can have side effect. In the following example I am calling handleClick function on the host component on click event.
<input type="button" (click)="handleClick()">

I can also do assignment here as in following case in case of input event I am assigning value of target element to the title property of host component.
<input type="text" (input)="title=$event.target.value">


Structural Directive - This is indicated by *, which indicates that they can upadate DOM element.
*ngFor -
*ngIf- Render content only if expression is true. Its not just hiding by css, but the dom element is not rendered. In case you want to hide the element you can use hidden property([hidden]="some expression")
*ngSwitchCase used along with non structural directive ngSwitch

For evaluating expression you should use ? against the object property which can be null, This will short circuit evaluation of the expression.

Styling
[ngStyle] return class and style. Using this you can style multiple properties of element.
[ngStyle]="{'background-color': 1===2?'green':'blue', 'font-weight': 'bold'}"     -> style="background-color: blue; font-weight: bold;"

You can also use [style.background-color]="'blue'". Here we directly accessing style property of the element. Refer above for property binding


[ngClass] - This allows to update classed on the element. It is specified as key and boolean expression value
<div [ngClass]="{'small-text': 1===1, 'red'}"> => class="small-text red"

Property and Attribute

Property and Attribute are more often used interchangeably. When defining an html element you can specify its attribute and when browser parses code, a corresponding DOM object will be created, which will have its properties. For example the following element has three attributes id, type and value.

<input id="myElement" type="text" value="something" >

Once browser create DOM, this object will contain multiple properties like attributes, className, disabled, hidden, width, id, innerText, innerHtml, value, type, style etc. Write following javascript and inspect different properties on the element. You will notice attribute property which will include add the attribute defined in the html element.

let input1 = document.getElementById("3");

Property and attributes doesn't have one to one relationship, but more often many of the properties relates to attributes.

Projection

This enables to build reusable component by giving option to injecting mark up by consumer of the component. Here we saying that my-component will show <h4> tag as it is in this component and will be shown everywhere where we use my-component. The consumer also has option of passing content which will replace ng-content. You can multiple ng-contect and have selector which will give option to inject multiple content.

@Component({
    selector: "my-component",
    template: `
    <h4>something which will be shown everywhere</h4>
<div (click)="toggelContent()" class="well thubnail">
        <ng-content select=".title"></ng-content>
        <ng-content select="[body]"></ng-content>
    </div>

`,
})


You can use this component like this.

<my-component>
<div class="title">
my title
</div>
<div body>
my body
</div>
</my-component>

Mar 17, 2017

Angular 2 High level overview

Angular 1 was based on MVC framework which has a View/Template which can have one or more controller, which expose modal.

In Angular 2, you have a component which has associated template and as with angular 1 you have model which represent data. Component and template has 1-1 relation. Any angular 2 application has root application component that is loaded first and then the angular router load the appropriate component by looking at the url. The component template is then displayed in the browser and the component may then load some data from the server and give it to the template to display. Component can be composed of other components which is the typical case in any complex page. This can be considered as a tree like structure, when you load to a new page your root app component remains same and below that, router loads the corresponding component and its sub component, by looking at the new route. As your application gets bigger, this can become a lot of stuff to load into memory. This is where angular module (ngModule) comes in picture, which are the container that groups all these routes and component trees. Modules can be loaded independent of each other. Browser will load only the module which is being accessed.

Angular Module (ngModule) file has following main pieces.

The imports array
The module's imports array appears exclusively in the @NgModule metadata object. It tells Angular about specific other Angular modules — all of them classes decorated with @NgModule — that the application needs to function properly.

The JavaScript import statements give you access to symbols exported by other files so you can reference them within this file.

The declarations array
This tells which component belongs in this module

Bootstrap array
The bootstrapping process creates the component listed in the bootstrap array and insert each one on the browser DOM.


Refer this for good high level overview of angular2.

Refer this for quick start project. Also you can use angular cli tool to get started with the angular project.