Lazy Load components in Angular using Locality

At the time of its creation, Angular apps load all modules immediately irrespective of their utility and usage in the app. Enter lazy loading. To reduce the number of components the app needs to load and save on resources such as processor power and network bandwidth, we implement the lazy loading pattern in the app. Lazy loading helps keep initial bundle sizes smaller, which in turn helps decrease load times.
Lazy loading of single components has not been possible so far. However, with Angular Ivy (or just Ivy), more abilities are now possible.

Locality in Ivy

Modules are the main building blocks of Angular. These contain several components, directives, pipes, and services. In layman’s terms, today’s application cannot exist without these modules.
Ivy introduces the concept of ‘Locality’ in which a component can exist without a module. With Locality, all the metadata is local to that particular component.
A real-world application of Lazy Loading of Component
Create a new application using Angular CLI. Our app.component.ts file will look like this:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { Component } from '@angular/core' ;
@ Component ({
selector: 'app-component' ,
templateUrl: './app.component.html' ,
styleUrls: [ './app.component.scss' ]
})
export class AppComponent {
title = 'my-app' ;
}
import { Component } from '@angular/core'; @Component({ selector: 'app-component', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'my-app'; }
import { Component } from '@angular/core';
@Component({
	selector: 'app-component',
	templateUrl: './app.component.html',
	styleUrls: ['./app.component.scss']
})
export class AppComponent {
	title = 'my-app';
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
ng g greet — flat — skip-import
ng g greet — flat — skip-import
ng g greet  — flat — skip-import

In the above command, skip-import will not import the component in the current module. We will load this component inside the module using lazy load.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { Component, OnInit } from '@angular/core' ;
@ Component ({
selector: 'greet' ,
templateUrl: './greet.component.html' ,
styleUrls: [ './greet.component.scss' ]
})
export class GreetComponent implements OnInit {
constructor () { }
ngOnInit () {
}
}
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'greet', templateUrl: './greet.component.html', styleUrls: ['./greet.component.scss'] }) export class GreetComponent implements OnInit { constructor() { } ngOnInit() { } }
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'greet',
  templateUrl: './greet.component.html',
  styleUrls: ['./greet.component.scss']
})
export class GreetComponent implements OnInit {
  constructor() { }
  ngOnInit() {
  }
}

We see that the greet component is created and we will pass data to this component,

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@ Input () message: string;
@ Output () sendEventEmmiter = new EventEmitter ()
@Input() message: string; @Output() sendEventEmmiter = new EventEmitter()
@Input() message: string;
@Output() sendEventEmmiter = new EventEmitter()

For now, this is sufficient for the greet component. We will now lazy load the greet component in the app.component. To do this, we have to inject

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
viewContainerRef and ComponentFactoryResolver
constructor ( private vcrf: ViewContainerRef, private cfr: ComponentFactoryResolver ) { }
viewContainerRef and ComponentFactoryResolver constructor(private vcrf: ViewContainerRef, private cfr: ComponentFactoryResolver) { }
viewContainerRef and ComponentFactoryResolver
constructor(private vcrf: ViewContainerRef, private cfr: ComponentFactoryResolver) { }

What is viewContainerRef? – This is a container in which one or more views can be attached
What is ComponentFactoryResolver? – This is a simple registry that maps Components to generated ComponentFactory classes.
These classes can be used to create instances of components. Use these to obtain the factory for a given component type, then use the factory’s create() method to create a component of that type.

Create the method

Now create the method to lazy load the component in app.component

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
loadComponent () {
this . vcrf . clear () ;
import ( './greet/greet.component' ) . then (({ GreetComponent }) = > {
let greetComp = this . vcrf . createComponent (
this . cfr . resolveComponentFactory ( GreetComponent )
) ;
}) ;
}
loadComponent() { this.vcrf.clear(); import('./greet/greet.component').then(({ GreetComponent }) => { let greetComp = this.vcrf.createComponent( this.cfr.resolveComponentFactory(GreetComponent) ); }); }
loadComponent() {
  this.vcrf.clear();
  import('./greet/greet.component').then(({ GreetComponent }) => {
    let greetComp = this.vcrf.createComponent(
      this.cfr.resolveComponentFactory(GreetComponent)
    );
  });
}

Here we are using promises of JavaScript. These allow us to load the component only if the promise returns successfully. We are also using viewContaierRef, and it’s method createComponent() in which we are passing componentFactoryResolver. These should be able to create the component and host inside that particular viewContainerRef.
If you see, we still are not passing any value to the greetComponent. In the above code, you will notice that we have a variable called greetComp. This variable contains a reference to a lazy loaded component that we can use to pass data.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
greetComp. instance . message = 'I am from app.component' ;
greetComp. instance . sendEventEmmiter . subscribe ( data = > {
console. log ( data ) ;
}) ;
greetComp.instance.message = 'I am from app.component'; greetComp.instance.sendEventEmmiter.subscribe(data => { console.log(data); });
greetComp.instance.message = 'I am from app.component';
greetComp.instance.sendEventEmmiter.subscribe(data => {
  console.log(data);
});

When we combine all the above code so then our loadComponent() method will look like this,

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
loadComponent () {
this . greetViewchildRef . clear () ;
import ( './greet/greet.component' ) . then (({ GreetComponent }) = > {
let greetComp = this . greetViewchildRef . createComponent (
this . cfr . resolveComponentFactory ( GreetComponent )
) ;
greetComp. instance . message = 'I am from app.component' ;
greetComp. instance . sendEventEmmiter . subscribe ( data = > {
console. log ( data ) ;
}) ;
}) ;
}
loadComponent() { this.greetViewchildRef.clear(); import('./greet/greet.component').then(({ GreetComponent }) => { let greetComp = this.greetViewchildRef.createComponent( this.cfr.resolveComponentFactory(GreetComponent) ); greetComp.instance.message = 'I am from app.component'; greetComp.instance.sendEventEmmiter.subscribe(data => { console.log(data); }); }); }
loadComponent() {
  this.greetViewchildRef.clear();
  import('./greet/greet.component').then(({ GreetComponent }) => {
    let greetComp = this.greetViewchildRef.createComponent(
      this.cfr.resolveComponentFactory(GreetComponent)
    );
    greetComp.instance.message = 'I am from app.component';
    greetComp.instance.sendEventEmmiter.subscribe(data => {
      console.log(data);
    });
  });
}

Displaying the result

To display the result, we have to load the greetComponent in the app.component.html file.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
< div >
< ng-template #greetComp>
< /ng-template >
< /div >
< button ( click ) = "loadComponent()" > Load component < /button >
<div> <ng-template #greetComp> </ng-template> </div> <button (click)="loadComponent()">Load component</button>
<div>
  <ng-template #greetComp>
  </ng-template>
</div>
<button (click)="loadComponent()">Load component</button>

Here we use the ng-template to load the greetComponent. We also need to add viewChild() to show the component data.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@ ViewChild ( 'greetComp' , { read: ViewContainerRef })
private greetViewchildRef: ViewContainerRef
@ViewChild('greetComp', {read: ViewContainerRef}) private greetViewchildRef: ViewContainerRef
@ViewChild('greetComp', {read: ViewContainerRef})
private greetViewchildRef: ViewContainerRef

Note that if we want to use any module, then we need to add the decorator to the component itself, and then import the module within it.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@ NgModule ({
declarations: [ GreetComponent ] ,
imports: [ FormsModule ]
})
class GreetComponentModule {}
@NgModule({ declarations: [GreetComponent], imports: [FormsModule] }) class GreetComponentModule {}
@NgModule({
  declarations: [GreetComponent],
  imports: [FormsModule]
})
class GreetComponentModule {}

Conclusion

We can create the component using a normal flow. However, what if we want to use the created component only for a specific action? If we use the usual way, we can reduce our application load by using a lazy load component.
To view the full application click here: https://stackblitz.com/edit/lazy-load-component.If you liked this post, here are a few more that may interest you:

Learn More about Encora

We are the software development company fiercely committed and uniquely equipped to enable companies to do what they can’t do now.

Learn More

Global Delivery

READ MORE

Careers

READ MORE

Industries

READ MORE

Related Insights

Enabling Transformation in Hospitality through Technology-Led Innovation

As the exclusive sponsor of the 2024 Hotel Visionary Awards, we support organizations leading ...

Read More

Key Insights from HLTH 2024: The Future of Patient-Centered Healthcare

Discover key insights from HLTH 2024 on digital health, AI in diagnostics, data interoperability, ...

Read More

Data-Driven Engineering: Transforming Operations and Products from Insight to Impact

Discover how data-driven engineering transforms operations and product development, enhancing team ...

Read More
Previous Previous
Next

Accelerate Your Path
to Market Leadership 

Encora logo

Santa Clara, CA

+1 669-236-2674

letstalk@encora.com

Innovation Acceleration

Speak With an Expert

Encora logo

Santa Clara, CA

+1 (480) 991 3635

letstalk@encora.com

Innovation Acceleration