Total Pageviews

Monday 24 June 2019

Preloading in Angular 7


When user navigates to the lazy loadable section of the application then the router has to fetch the required module from the server which can take time. In this case Preloading is a very helpful concept, in this router downloads or preloads the lazy loadable module asynchronously in background.

This speed up the load time of angular applications.

Preloading can be done in 4 steps;

1.    Initial Load where all the necessary components load to bootstrap the application.
2.    Bootstrap where application initializes with required modules.
3.    Preloading, in this router, preloads modules in background while app is running and user interacts with the application.
4.    Now once the preloading is done user clicks on lazy loadable module where navigation is instant and fast.

To enable preload, we can pass a preloading strategy into forRoot. Angular provides two inbuilt strategies –
  • NoPreloading— This is default behavior i.e. no module will be preloaded.
  • PreloadAllModules — All modules will be preloaded as fast as possible.
In PreloadAllModules, we can start by adding a data object to the route’s config:

import { NgModule } from '@angular/core';
import { RoutesRouterModulePreloadingStrategy } from '@angular/router';

import { LoginComponent } from './login/login.component';
import { HomeComponent } from './home/home.component';
import { RegisterComponent } from './register/register.component';
import { CustomPreloadingStrategy } from './register/custom-preloading-strategy';

const routesRoutes = [{
    path: "",
    redirectTo: "/login",
    pathMatch: 'full'
  },
    {
        path: 'login',
        component: LoginComponent
    },
    {
        path: 'home',
        component: HomeComponent
    },
    {
        path: 'register',
        loadChildren: "./register/register.module#RegisterModule",
        data:{preload:true}
    }
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { preloadingStrategy : CustomPreloadingStrategy } )],
  exports: [RouterModule],
  providers: [CustomPreloadingStrategy]
})
export class AppRoutingModule { }


this data object has two boolean properties:

·         preload — To preload module or not
·         delay — To preload module with some delay

Now we will create CustomPreloadingStrategy class, in which there is a preload method which takes two parameters: a route and the function that actually does the preloading. In it we check if the preload property is set to true. And if it is true then we will call the load function.

import { Observableofobservable } from 'rxjs';
import { PreloadingStrategyRoute } from '@angular/router';
import { Injectable } from '@angular/core';

@Injectable()
export class CustomPreloadingStrategy implements PreloadingStrategy {
    preload(routeRouteload: () => Observable<any>): Observable<any> {
   
        if (route.data && route.data['preload']) {
          console.log('preload called');
          return load();
       } else {
          console.log('no preload');
          return of(null);
        }
      }
    
}


The first parameter is the active Route. We use this to extract the information about the route, which is being loaded.

The second parameter is Observable function, which we need to return if we want to preload this module. We can return Observable of null, if we do not want to preload the module.

Finally, we need to enable the strategy by passing it to the provider and to RouterModule.forRoot.

@NgModule({
  imports: [RouterModule.forRoot(routes, { preloadingStrategy : CustomPreloadingStrategy } )],
  exports: [RouterModule],
  providers: [CustomPreloadingStrategy]
})
export class AppRoutingModule { }





Thursday 20 June 2019

Angular 7 | Can't bind to 'formGroup' since it isn't a known property of 'form'


If there are multiple module files in application then only adding ReactiveFormsModule in app.module.ts is not enough.



import { FormsModule, ReactiveFormsModule } from '@angular/forms';`

@NgModule({
  declarations: [
    AppComponent,
  ]
  imports: [
    FormsModule,
    ReactiveFormsModule,
    RegisterComponent,
],
...



This will not work, when I use a [formGroup] directive from a component added in another module, e.g. using [formGroup] in register.component.ts which is subscribed in register.module.ts file:

import { NgModule }       from '@angular/core';
import { CommonModule }   from '@angular/common';
import { RegisterComponent } from './author.component';

@NgModule({
  imports: [
    CommonModule,
  ],
  declarations: [
    RegisterComponent,
  ],
  providers: [...]
})
export class RegisterModule {}



By default ReactiveFormsModule would be inherited by all its children modules like register.module but this is not true in this case. We need to import ReactiveFormsModule in register.module.ts in order to make all directives to work:



import { FormsModule, ReactiveFormsModule } from '@angular/forms';
...

@NgModule({
  imports: [
    ...,
    FormsModule,    //added here too
    ReactiveFormsModule //added here too
  ],
  declarations: [...],
  providers: [...]
})
export class RegisterModule {}



So, the conclusion is if there are submodules in application, then make sure to import ReactiveFormsModule in each submodule file.

Wednesday 19 June 2019

Lazy Loading in Angular 7


By default, NgModules are eagerly loaded i.e. as soon as app loads, so do all the NgModules. But for large apps with many routes, lazy loading is very helpful.

Lazy loading loads the components asynchronously when a specific route is activated or when required. It helps to increase the performance and speed of the application. It splits the app into multiple bundles.

Lazy loading was implemented in the Angular router (@angular/router) to fix this. 

Feature module is that module which you want to download when required.

Below is the step by step example of lazy loading:

1) Create a new project with routing option

ng new my-app –routing

2) Create two components - login and register

ng generate component login
ng generate component register

3) Create respective module files in each component folder     as below:

register.module.ts

4) Create a respective router module file in each component folder

register-routing.module.ts

Now my project structure will look like below:


5) Import router module in app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';


@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


Remove register component import and declaration from app.module.ts, as each view will have their own module defined.


6) Add code in component routing

my-app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RegisterComponent } from './register.component';

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

const routes: Routes = [
  {
    path: '',
    component: RegisterComponent
  }];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class RegisterRoutingModule { }



By using forChild we will call child modules (featured module) in app’s main routing module.

In my-app.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { RegisterRoutingModule } from './register-routing.module';
import { RegisterComponent } from './register.component';

import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [RegisterComponent],
  imports: [
    CommonModule,
    ReactiveFormsModule,
    RegisterRoutingModule
  ]
})
export class RegisterModule { }


Then in app’s main routing module we will define Routes using loadChildren attribute. The loadChildren module uses # to define each independent module’s name.


In app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { LoginComponent } from './login/login.component';
import { RegisterComponent } from './register/register.component';

const routes: Routes = [{
    path: "",
    redirectTo: "/login",
    pathMatch: 'full'
  },
    {
        path: 'login',
        component: LoginComponent
    },
    {
        path: 'register',
        loadChildren: './register/register.module#RegisterModule'
    }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }


And finally add links to Route/Open views

register.component.html

<button [disabled]="loading" class="btn btn-primary" routerLink="register">Register</button>


Now run application using by using below command:

ng-serve

Which will produce below output.



At first only login module will load see attached screenshot



After clicking on register button, register module will load.


Hope this helps. 







Microsoft Logo using flexbox and Reactjs

 <!DOCTYPE html> <html> <head>     <script src="https://unpkg.com/react@18/umd/react.development.js" crossori...