Lazy loading Recipes 🚀

🥱🔃🍳

Pankaj P. Parkar

Sr. Technology Consultant, Virtusa

  • MS MVP

  • Angular GDE

  • Opensource Maintainer

  • Stackoverflow Topuser

About Me!

What is Lazy Loading?

It is technique of loading relevant resources on demand

pankajparkar

Lazy Loading Recipes

  1. Dynamic Loading Component
  2. Import + SCAM
  3. Config based simple form - ngOutletComponent
  4. Config based complex form

pankajparkar

Load Component Dynamically

@ViewChild('dynamicComponent', { read: ViewContainerRef }) dynamicComponent: any;
constructor(
  private factoryResolver: ComponentFactoryResolver
) { }

showBusinessCard() {
  this.clear();
  const compFactory = this.factoryResolver.resolveComponentFactory(BusinessCardComponent);
  const compRef = this.dynamicComponent.createComponent(compFactory);
  compRef.instance.profile = this.profile;
}
clear() {
  this.dynamicComponent.clear();
}
<button (click)="showBusinessCard()">
  Show Business Card
</button>
<ng-container #dynamicComponent></ng-container>

pankajparkar

Import + SCAM

 (Single Component Angular Module)

Weather Forecast Widget

pankajparkar

Source - https://github.com/pankajparkar/weather-cast

Import + SCAM

 (Single Component Angular Module)

/* imports */

@Component({
  selector: 'wc-weather-dashboard',
  templateUrl: './weather-dashboard.component.html',
  styleUrls: ['./weather-dashboard.component.css']
})
export class WeatherDashboardComponent implements OnInit, OnDestroy {

  @Input() headingStart = 'Weather Forecast in';
  ...
}

// important to export NgModule from component file
@NgModule({
  declarations: [
    WeatherDashboardComponent,
    ...
  ],
  imports: [
    ...
  ],
  exports: [WeatherDashboardComponent]
})
export class WeatherForecastModule { }

pankajparkar

 (Single Component Angular Module)

@ViewChild('container', { read: ViewContainerRef }) container: any;

constructor(
  private factory: ComponentFactoryResolver
) { }

async loadWeatherWidget() {
  this.container.clear();
  const weatherComponent =
   await import('../weather-forecast/weather-dashboard/weather-dashboard.component')
    .then(i => i.WeatherDashboardComponent);
  const weatherForecastWidget = this.factory.resolveComponentFactory(weatherComponent);
  const componentRef = this.container.createComponent(weatherForecastWidget);
  componentRef.instance.headingStart = 'Just for fun';
}
<button (click)="loadWeatherWidget()">
    Load Weather Widget
</button>
<ng-container #container></ng-container>

Import + SCAM

pankajparkar

Config Based Simple Form

(*ngComponentOutlet)

<form (ngSubmit)="submit()">
    <h3>Feedback Form</h3>
    <div *ngFor="let control of controls">
        <ng-container 
            *ngComponentOutlet="control.component | async">
        </ng-container>
    </div>
    <button mat-raised-button>
        Submit
    </button>
</form>
  controls: {component?: Promise<any>|null}[] = [
   { component: import('./controls/currency/currency.component').then(c => c.CurrencyComponent) },
   { component: import('./controls/number/number.component').then(c => c.NumberComponent) },
   { component: import('./controls/select/select.component').then(c => c.SelectComponent) },
   { component: import('./controls/slider/slider.component').then(c => c.SliderComponent) },
  ];

pankajparkar

Config based Complex Form 

(ng-dynamic-componet)

componentsMap: {[key: string]: Promise<any>|null} = {
  currency: import('./../controls/currency/currency.component').then(m => m.CurrencyComponent),
  number: import('./../controls/number/number.component').then(m => m.NumberComponent),
  select: import('./../controls/select/select.component').then(m => m.SelectComponent),
  slider: import('./../controls/slider/slider.component').then(m => m.SliderComponent),
};

controls: Controls[] = [
 { type: 'currency',inputs:{value: 1000, formControlName: 'price', group: this.feedbackForm}},
 { type: 'number',inputs:{formControlName: 'age', value: 100, group: this.feedbackForm}},
 { type: 'select',inputs:{options: ['Mumbai', 'Pune'], formControlName: 'city', value: 'Mumbai'}},
 { type: 'slider',inputs:{formControlName: 'rating', value: 1, group: this.feedbackForm}},
];

constructor() { }

createForm(controls: Controls[] = []) {
  controls.forEach(control => {
    this.feedbackForm.addControl(
      control.inputs.formControlName,
      new FormControl(control.inputs.value || '')
    );
  });
}

pankajparkar

Config based Complex Form 

(ng-dynamic-componet)

<form [formGroup]="feedbackForm" (ngSubmit)="submit()">
    <h3>Profile Form</h3>
    <div *ngFor="let control of controls">
        <ng-template [ngComponentOutlet]="componentsMap[control.type] | async"
            [ndcDynamicInputs]="control.inputs"
        ></ng-template>
    </div>
    <button mat-raised-button>
        Submit
    </button>
</form>

pankajparkar

pankajparkar

Standalone Components on the way

Source - https://github.com/angular/angular/pull/42831

Q & A

pankajparkar

pankajparkar

pankajparkar

References

Lazy Loading Recipes

By Pankaj Parkar

Lazy Loading Recipes

lazy-loading-recipes

  • 1,356