Implementing The Strategy Pattern Using Lazy-Loaded Components in Angular Version 9
Tags: angular, typescript, math, angular9
Published: 2021-05-06 16:05:23

Jim Armstrong | ng-conf | Apr 2020

Simply stated, the _Strategy Pattern_ is a behavioral pattern that governs the selection of different algorithms or procedures for solving a common problem at runtime. Many times, this pattern is implemented by loading a computational library that conforms to an _Interface_ and is applied uniformly by one or more application components.

In front-end applications, a _strategy_ may involve more than just an algorithm or library API. There is often need to load one of several different implementations of an entire view based on runtime criteria. In an Angular setting, we may think of this as needed to lazy-load a _Module_, but it is even more helpful if we can load individual components, outside any _Module_ definition. Enter Angular Version 9.

In the article below, I covered dynamic component generation inside lazy-loaded routes, with the ability to control component display via JSON data,

[Dynamic Component Generation in Lazy-Loaded Routes](https://medium.com/ngconf/dynamic-component-generation-in-lazy-loaded-routes-d2e0f9e89c57) — Exploit Data Driven Component Layout, Loaded On-Demand in Angular

Three components were dynamically generated inside a lazy-loaded route and displayed in an order dictated by a data file. However, since components prior to Angular Version 9 were required to exist in a _Module_ definition, each component was defined in the _entryComponents_ section of the route’s _Module_. Each component was loaded into the application when the route was lazy-loaded, even if the component was not actually required.

Angular Version 9 provides the ability to lazy-load individual components that are outside the scope of any _Module_. This allows for a very powerful implementation of the _Strategy Pattern_.

### **The Application**

The sample application for this article is a mashup of multiple requirements from past applications across Flash, Flex, and Angular. The application illustrates two different solutions to the point-in-circle problem, i.e. identify the circles in a collection for which a single point is in the strict interior.

Now, if it was just a matter of selecting an algorithm to solve the problem and then display the results in a single view, the _strategy_ could be implemented with a lazy-loaded JavaScript library (a topic for another article). In this demo, the results are viewed differently, not only in terms of layout, but with different render environments. Each view renders a simulation in which the point moves inside the view area and the simulation updates the point/circle intersections. However, one algorithm is rendered into a Canvas context and the other into SVG. The Canvas and SVG displays also differ based on algorithm characteristics.

Because of the differing views and dramatically different dependencies between views, this problem is best solved by lazy-loading an individual component (and its dependencies).

Before deconstructing the application, I wish to point out that is is **not** an article on ‘how to’ lazy-load Components in Angular Version 9. A Google search will return about half a dozen good articles on the steps involved in this process. Instead, this article discusses how to build a complete application around the technique.

And, on that note, here is the GitHub for the complete application.

[theAlgorithmist/Angular9-Strategy-Pattern](https://github.com/theAlgorithmist/Angular9-Strategy-Pattern)

### **Algorithms and Geometry**

Well, let’s get this out of the way early. This is an Angular article, not a math/algorithms article. As a consequence, the two algorithms I chose for the demonstration are rather rudimentary and easy to follow. As far as the necessary math, here is everything we need.

Blah, blah … math … blah, blah … geometry … blah blah … API.

There, we’re finished :). Everything you need is encapsulated away into Typescript libraries in the _/src/app/shared/libs_ folder. I even gave you a bonus — a number of pure functions for operations involving circles from my private Typescript Math Toolkit library.

The two algorithms implemented in this demo were chosen to illustrate techniques you may find helpful in future applications. In one case, there could be an arbitrary (and large) number of circles, but the circles do not move (only the point moves). In the second case, there are a modest number of circles (hundreds) and a small percentage of them are expected to move each simulation step along with the point.

Both the point and circles move according to a [random walk](https://en.wikipedia.org/wiki/Random_walk). Don’t worry — remember the power of the API — it’s all done for you :)

The first algorithm (simulation rendered into a Canvas) uses a simple quad map. The viewable area is divided into quadrants. The Typescript Math Toolkit basic circle class automatically computes quadrant locations given bounds, so a quad map is very easy to implement. Since the circles never move, the map need only be initialized once before the simulation begins.

The second algorithm (simulation rendered into SVG) is designed for a situation where there are a modest number of circles (hundreds), and a small percentage of them move at each time step. All circles are tested for point intersection, but the test is optimized to return false quickly. It is more expensive to test for full intersection, so instead of testing _‘if something is true, then do the following operation,’_ it is more efficient to test _‘if something is false, skip and go to the next one.’_ It’s very easy to quickly return false for the intersection test and that is the majority expectation for most tests.

Common (visual) operations for each display include indicating the specific circles that contain the test point at each simulation step. Previous visual indications from a prior simulation step must be reset to default display at the next time step. Beyond that, the Canvas display shows the quadrants and highlights the current quadrant in which the test point lies. The SVG display only shows the circles and test point.

It’s only necessary to understand the algorithms employed in both simulations at a very high level. In fact, the only reason to dive deeper into their implementation is if you want to improve the point-circle intersection algorithm further.

### **Application Deconstruction**

Let’s look at each of the application requirements, and then discuss how they are all integrated together. We need

1 — Two components to implement each algorithm and each set of display requirements for a single simulation. Commonality among these components should be specified in an _Interface_.

2 — Lazy-load only one of the components based on some runtime criteria (an injected algorithm ID, for example).

3 — Create a means to provide inputs and handle component outputs.

4 — Run the simulation, i.e. advance one step at regular time intervals.

For demonstration purposes, the main app component, _/src/app/app.component.ts_, serves as the smart component that lazy-loads one of the two point-in-circle simulation components. The main app module allows specification of an algorithm ID (1 for the first algorithm and Canvas render, 2 for the second algorithm and SVG render).

```
import { BrowserModule } from '@angular/platform-browser';
import { NgModule      } from '@angular/core';

import { AppComponent  } from './app.component';
import { CircleService } from './shared/services/circle-service';

// Injectable constants
import { ALGORITHM_ID } from './tokens';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule
  ],
  providers: [
    CircleService,
    { provide: ALGORITHM_ID, useValue: 1 },
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

This ID is injected into the main app component and then used to select the run-time _strategy_ for the point-in-circles simulation. Change the value from 1 to 2 in order to lazy-load a different simulation component.

The two point-in-circle simulation components are

Algorithm 1 (Canvas): _/src/app/components/point-in-circle-1/pic-1.component.ts_

Algorithm 2 (SVG): _/src/app/components/point-in-circle-2/pic-2.component.ts_

Since everything is driven by the main app component, let’s look at that one in detail.

### **Main App Component**

This component, in _/src/app/app.component.ts_ is the smart component that lazy-loads one of two presentational components based on an algorithm ID. Although the algorithms and the display employed by each of these presentational components is different, as far as the rest of the application is concerned, they have a common set of inputs, outputs, and an exposed API. These are defined in the _Interface_ in _/src/app/shared/interfaces/pic-component.ts,_

```
import { OnChanges } from '@angular/core';
import { Subject   } from 'rxjs';

export interface IPointInCircle extends OnChanges
{
  intersect$: Subject<string>;

  next: () => void;

  step: number;
}
```

The simulation step (controlled by the smart component) is an _Input_ to the point-in-circle component. This component is not statically defined in a template (there is no known binding to that _Input_), so Angular does not know to call the _ngOnChanges_ lifecycle method. As a result, the smart component must do this manually. So, each lazy-loaded component must implement the _OnChanges_ interface. Each of these components must also provide a _next()_ method in order to advance the simulation one step.

While there are several approaches to wiring up component outputs, I personally prefer a reactive approach. Each of the lazy-loaded components must expose a _`Subject<string>`_ to indicate that the point intersected a circle with a particular id. The smart component that lazy-loads one of the two point-in-circle components simply subscribes to _intersect$_.

This interface is the only knowledge the smart component has about the two lazy-loaded presentational components.

Typical practice for lazy-loaded components is to place them into an _ng-container_, and this is the case for the main _view_ in this application, _/src/app/app.component.html_,

```
<p>Algorithm ({{algorithm}} Render into: {{render}})</p>
<p>Total intersections: {{intersections}}</p>

<ng-container #picContainer></ng-container>
```

The template variable is used to assign a _ViewChild_ in _/src/app/app.component.ts_,

```
@ViewChild('picContainer', {static: true, read: ViewContainerRef})
private picContainer: ViewContainerRef;
```

The main app component receives the algorithm ID and all other classes necessary for lazy-loading through injection,

```
constructor(@Inject(ALGORITHM_ID) public algorithm: number,
            private _compFactoryResolver: ComponentFactoryResolver,
            private _injector: Injector)
{
  this.render = RenderTargetEnum.CANVAS;

  this.ComponentInstance = null;

  this._duration     = 1000;
  this._delta        = 500;
  this._currentStep  = 0;
  this.intersections = 0;
}
```

The _render_ variable indicates whether the rendered output is Canvas or SVG. The _ComponentInstance_ variable is a _`ComponentRef<IPointInCircle>`_. The _instance_ property of that variable allows direct calls to the presentational component after lazy-loading.

A duration of 1000 time steps at increments of 500 msec is set in the constructor along with the current step number of zero and a total intersection count of zero.

On initialization, the component begins the simulation via a call to the private  ___initSimulation()_ method, whose relevant code is shown below.

```
await this.__loadComponent();

    if (this.ComponentInstance)
    {
      // on every intersection
      this.ComponentInstance.instance.intersect$.subscribe( (id: string) => this.__updateIntersection(id) );

      // begin simulation
      timer(100, this._delta)
        .pipe(
          map( (msec: number): void => {
            this._currentStep++;

            if (this._currentStep > this._duration) {
              this.destroy$.next();
              this.destroy$.complete();
            }
          }),
          takeUntil(this.destroy$)
        )
      .subscribe( () => {
        this.ComponentInstance.instance.ngOnChanges({
          step: new SimpleChange(this._currentStep-1, this._currentStep, this._currentStep === 1)
        });

        // run the next simulation step
        this.ComponentInstance.instance.next();
      });
    }
```
###### [__initSimulation](https://gist.github.com/theAlgorithmist/7b6b1dbb2e07068690fedff5e6350b04#file-__initsimulation) hosted by GitHub 

You could place this code in the _then_ clause of a _Promise_, but I personally prefer _asyc/await_ (although beware there is a known problem with this if your target is ES2017). Component lazy-loading is shown below,

```
private async __loadComponent(): Promise<any>
  {
    let factory: ComponentFactory<IPointInCircle>;

    if (this.picContainer) {
      this.picContainer.clear();
    }

    // lazy-load the required component based on the algorithm id
    switch (this.algorithm)
    {
      case 1:
        const {Pic1Component}  = await import('./components/point-in-circle-1/pic-1.component');
        factory                = this._compFactoryResolver.resolveComponentFactory(Pic1Component);
        this.ComponentInstance = this.picContainer.createComponent(factory, null, this._injector);

        this.render = RenderTargetEnum.CANVAS;
        break;

      case 2:
        const {Pic2Component}  = await import('./components/point-in-circle-2/pic-2.component');
        factory                = this._compFactoryResolver.resolveComponentFactory(Pic2Component);
        this.ComponentInstance = this.picContainer.createComponent(factory, null, this._injector);

        this.render = RenderTargetEnum.SVG;
        break;
    }
  }
```
###### [gistfile1.txt](https://gist.github.com/theAlgorithmist/0effc34344fefe76161538f479de5564#file-gistfile1-txt) hosted by GitHub

Following is the relevant block of code for lazy-loading the component associated with algorithm #1,

```
const {Pic1Component} = await import('./components/point-in-
circle-1/pic-1.component');
factory = 
this._compFactoryResolver.resolveComponentFactory(Pic1Component);
this.ComponentInstance = 
this.picContainer.createComponent(factory, null, this._injector);
```

It is very important to place the precise path of the lazy-loaded component as a string literal inside the _import_. For example,

```
const url: string = './components/point-in-circle-1/pic-1.component';
.
.
.
const {Pic1Component} = await import(url);
```

compiles with a warning, and the application will not run.

The destructuring assignment must reference an exported _Object_ from the referenced file, in this case, _Pic1Component_.

Once a point-in-circle simulation component is lazy-loaded, the following blocks of code in ___initSimulation()_ handle outputs, inputs, and the actual simulation,

```
this.ComponentInstance.instance.intersect$.subscribe( (id: string) 
=> this.__updateIntersection(id) );
```

This subscribes to the output from the simulation component and executes a handler every time the simulation detects a point-circle intersection.

The simulation is run within an RxJs _timer_.

```
timer(100, this._delta)
  .pipe(
    map( (msec: number): void => {
      this._currentStep++;

      if (this._currentStep > this._duration) {
        this.destroy$.next();
        this.destroy$.complete();
      }
    }),
    takeUntil(this.destroy$)
  )
.subscribe( () => {
  this.ComponentInstance.instance.ngOnChanges({
    step: new SimpleChange(this._currentStep-1, this._currentStep, this._currentStep === 1)
  });

  // run the next simulation step
  this.ComponentInstance.instance.next();
});
```

The variable _destroy$_ is a local _Subject_ that is used to indicate the end of simulation. This happens when the duration limit is reached or if the component is destroyed.

The parent (smart) component controls the step count of the simulation as it may later be desired to run a simulation forward or backward. The presentational (simulation) component accepts this step as an _Input_ and reflects it in its own UI.

The simulation (lazy-loaded) component _Input_ is accepted and processed through that component’s _ngOnChanges()_ method. That handler is called each time step with a new _SimpleChange_ object. Note that the call is made on the component reference’s _instance_ property.

```
this.ComponentInstance.instance.ngOnChanges({
    step: new SimpleChange(this._currentStep-1, this._currentStep, 
this._currentStep === 1)
```

and then, each iteration of the timer executes the next simulation step,

```
this.ComponentInstance.instance.next();
```

That concludes the deconstruction of the smart component that lazy-loads one of the point-in-circle simulation (or presentational) components. The simulation components are largely like any other Angular presentational component, but with one important exception. We’ll look at that next by deconstructing the Canvas-rendered component.

### **Lazy-Loaded Component Structure**

The lazy-loaded simulation component for the first algorithm looks largely like any other component. This is the template,

_/src/app/components/point-in-circle-1/pic-1.component.html_

```
<div pic-canvas
     class="circlesContainer"
     [strokeWidth]="1"
     [strokeColor]="'0x0000ff'"
     [gridColor]="'0xff0000'"
     (onIntersect)="onIntersection($event)">
</div>
<p>Simulation Step: {{step}}</p>
```

An attribute _directive_ is used to delegate Canvas creation (via PIXI.js), computations, and rendering. In addition to defining class properties necessary to fulfill the _IPointInCircle_ interface, a _ViewChild_ is defined for the attribute _directive_,

```
export class Pic1Component implements IPointInCircle, OnChanges
{
  public intersect$: Subject<string>;

  @Input()
  public step: number;

  @ViewChild(PicCanvasDirective, {static: true})
  protected _picContainer: PicCanvasDirective;

  constructor()
  {
    this.intersect$ = new Subject<string>();
  }
.
.
.
```

The next two methods complete the _IPointInCircle_ interface contract,

```
public ngOnChanges(changes: SimpleChanges): void
{
  let prop: string;
  let change: SimpleChange;

  for (prop in changes)
  {
    change = changes[prop];

    if (prop === 'step')
    {
      this.step = +change.currentValue;
    }
  }
}

public next(): void
{
  if (this._picContainer) {
    this._picContainer.next();
  }
}
```

Note that this is the _next()_ method that is called from the RxJs _timer_ subscription after _Pic1Component_ is lazy-loaded.

Note that _Pic1Component_ has an important dependency, the _PicCanvasDirective_. While Pic1Component may exist outside any _NgModule_ in the application, the directive still needs to be tied to the component of which it is a _ViewChild_ via a module definition. The cleanest way to do this and ensure that the directive is only loaded when _Pic1Component_ is loaded is to use a local (non-exported) module,

```
@NgModule({
  imports: [CommonModule],
  declarations: [
    Pic1Component,
    PicCanvasDirective
  ]
})
class PicCanvasModule {}
```

You will see a similar module in _/src/app/components/point-in-circle-2/pic-2.component.ts_ for the second simulation component.

Note that _Pic1Component_ (and _Pic2Component_, for that matter) have another dependency, the injected _CircleService_. This service currently contains read-only variables, but is not listed as a provider in the above _NgModule_, nor has an injector been configured for it. In this application, the lazy-loaded component is loaded into the application root, so we are using the root injector. Note that a provider for this service is contained in _/src/app/app.module.ts_. It is often the case that either the root or a route-level injector can be used for such purposes. Other tutorials on the mechanics of lazy-loading components describe how to configure an injector just for services used by a lazy-loaded component.

This is all the structure that is necessary to dynamically load and instantiate a complete simulation for the problem at hand using only an algorithm id to differentiate between the two simulations.

The final section is optional and deconstructs the _PicCanvasDirective_. It is not necessary to understand the details of this directive in order to build your own application with lazy-loaded components. So, free free to quit reading here :)

### **Inside A Simulation**

The reference file for this deconstruction is _/src/app/shared/libs/render/canvas-render/pic-canvas.directive.ts_

This is an attribute directive that creates a PIXI.js-generated _Canvas_ inside some _DOM_ container (typically a _DIV_). The directive employs a number of computational helper functions, as can be seen in the imports,

```
import { TSMT$Circle } from '../../circle';

import { CircleService } from '../../../services/circle-service';

import { canvasRenderCircle } from '../render-circle-canvas';
import { pointRandomWalk    } from '../../point-random-walk';
import { TSMT$PointInCircle } from '../../circle-util-functions';
import { TSMT$getQuadrant   } from '../../geom-util-functions';
import { RandomIntInRange   } from '../../random/RandomIntInRange';

@Directive({
  selector: '[pic-canvas]'
})
export class PicCanvasDirective implements OnInit, OnChanges
.
.
.
```

_TSMT$Circle_ is the Typescript Math Toolkit (a private library for which I have open-sourced some of the contents) basic circle class. This class is optimized for a quad-map as it automatically updates the quadrant location of a circle every time its coordinates are mutated (provided that bounds are set in advance). The class also handles the case where a circle may lie in more than one quadrant.

Quadrants in which circles are located are referenced by four Typescript _Record_ structures,

```
protected _quad1: Record<string, boolean>;
protected _quad2: Record<string, boolean>;
protected _quad3: Record<string, boolean>;
protected _quad4: Record<string, boolean>;
```

Relevant information about the DOM container for the Canvas (specifically width and height) is available in the _ngOnInit()_ handler, which is where most of the PIXI.js initialization is performed. The initial set of circles are also drawn at that time in the ___initCircles()_ method.

There are four class variables that store circle-related information. The first is __circleRefs_, an array that stores are reference to each _TSMT$Circle_ in the simulation. Every circle has a visual representation, a graphics context or display object in PIXI.js, which is stored in another array, __circleDO_.

When a circle is identified as containing the test point during a simulation step, the circle reference is placed into the __indentified_ array and its corresponding graphics context into the __identifiedDO_ array.

Here is the code for the circle initialization, which is responsible for placing circles throughout the simulation area. PIXI.js drawing has been covered in a number of my past articles and will not be discussed in the current deconstruction.

```
protected __initCircles(): void
{
  // Draw the point
  this.__drawPoint();

  // Draw the circles at pseudo-random locations around the drawing area
  const xHigh: number = (this._width - CircleService.MAX_RADIUS) + 0.499;
  const yHigh: number = (this._height - CircleService.MAX_RADIUS) + 0.499;

  let i: number;
  let x: number;
  let y: number;
  let r: number;
  let g: PIXI.Graphics;
  let c: TSMT$Circle;

  for (i = 0; i < CircleService.NUM_CIRCLES; ++i)
  {
    x = RandomIntInRange.generateInRange(CircleService.MAX_RADIUS, xHigh);
    y = RandomIntInRange.generateInRange(CircleService.MAX_RADIUS, yHigh);
    r = RandomIntInRange.generateInRange(CircleService.MIN_RADIUS, CircleService.MAX_RADIUS);
    g = new PIXI.Graphics();
    c = new TSMT$Circle();

    c.x      = x;
    c.y      = y;
    c.radius = r;
    c.id     = i.toString();   // id needs to double as the index into the master array of circle references

    // update quadrant(s) for the circle; this requires bounds to be set
    c.setBounds(0, 0, this._width, this._height);

    // the keys are what matter here ...
    if (c.inQuadrant(1)) {
      this._quad1[c.id] = true;
    }

    if (c.inQuadrant(2)) {
      this._quad2[c.id] = true;
    }

    if (c.inQuadrant(3)) {
      this._quad3[c.id] = true;
    }

    if (c.inQuadrant(4)) {
      this._quad4[c.id] = true;
    }

    this._circleRefs.push(c);
    this._circleDO.push(g);
    this._circles.addChild(g);

    g.lineStyle(this.strokeWidth, this.strokeColor);
    g.drawCircle(x, y, r);
  }
}
```
###### [__initCircles](https://gist.github.com/theAlgorithmist/442d45e9101a2ea37a60e865deb2b9c0#file-__initcircles) hosted by GitHub

The most important code (for this algorithm) occurs after placing the circles ‘randomly’ inside the display area.

```
c.setBounds(0, 0, this._width, this._height);

if (c.inQuadrant(1)) {
  this._quad1[c.id] = true;
}

if (c.inQuadrant(2)) {
  this._quad2[c.id] = true;
}

if (c.inQuadrant(3)) {
  this._quad3[c.id] = true;
}

if (c.inQuadrant(4)) {
  this._quad4[c.id] = true;
}
```

Each circle instance contains internal bounds that may be set by the caller. Bound setting and each subsequent coordinate mutation alters the quadrant in which the circle lies. That quadrant may be queried and is used to set the primitive quad-map (currently four separate _Records_ in _Pic1Directive_).

Most of the simulation work is performed in the _next()_ method that advances the simulation one step.

```
public next(): void
{
  let circ: TSMT$Circle;
  let g: PIXI.Graphics;

  // first, redraw any circles previously marked as containing the point with the default stroke color
  while (this._identifiedDO.length > 0)
  {
    g    = this._identifiedDO.pop();
    circ = this._identified.pop();

    canvasRenderCircle(g, circ, this.strokeWidth, this.strokeColor.toString());
  }

  /*
    random walk the point (realize that it could eventually 'walk' off the visible area; whether or not
    that is something that should be tested and compensated for is up to you
   */
  [this._px, this._py] = pointRandomWalk(this._px, this._py, CircleService.LOW_RADIUS, CircleService.HIGH_RADIUS);

  // draw the point and update the quadrant
  this.__drawPoint();

  this._curQuad = TSMT$getQuadrant(this._px, this._py, 0, 0, this._width, this._height);
  this.__drawQuadrants();

  // Only check circles in the quad in which the point is located
  if (this._curQuad > 0 && this._curQuad < 5)
  {
    // only update the id list if the quadrant changed
    if (this._curQuad != this._prevQuad)
    {
      this._prevQuad = this._curQuad;
      this._check    = Object.keys(this[`_quad${this._curQuad}`]);
    }

    this._check.forEach( (id: string): void =>
    {
      circ = this._circleRefs[+id];
      g    = this._circleDO[+id];
      if (TSMT$PointInCircle(this._px, this._py, circ.x, circ.y, circ.radius))
      {
        this._identified.push(circ);
        this._identifiedDO.push(g);

        g.clear();
        g.lineStyle(this.strokeWidth, '0xff0000');
        g.drawCircle(circ.x, circ.y, circ.radius);

        this.onIntersect.emit(id);
      }
    });
  }
}
```
###### [next.ts](https://gist.github.com/theAlgorithmist/fcd56980c47fd5d64ad689d412c2b999#file-next-ts) hosted by GitHub

It seems like a long method, but it performs a relatively simple number of steps. First, the __indentified_ array is used to redraw any circles identified as containing the point in the prior simulation step with their default visual properties.

The random walk for the point is executed and the coordinates updated in a destructuring assignment,

```
[this._px, this._py] = pointRandomWalk(this._px, this._py, 
CircleService.LOW_RADIUS, CircleService.HIGH_RADIUS);
```

The current quadrant occupied by the point (stored in the __curQuad_ class variable) is updated with a utility method,

```
this._curQuad = TSMT$getQuadrant(this._px, this._py, 0, 0, 
this._width, this._height);
```

The current quadrant is checked vs the prior quadrant from the previous simulation step. If the quadrant number changes, then it is necessary to adjust the subset of circles that are checked for point-circle intersection. For example, if the current quadrant is one and the prior quadrant is one, then the check is made against keys in the local __quad1 Record_. This variable might be unchanged for several simulation steps. If it changes to three, for example, tests for point-circle intersection should to be made against keys in the local __quad3 Record_. This is handled by the block of code,

```
if (this._curQuad != this._prevQuad)
{
  this._prevQuad = this._curQuad;
  this._check    = Object.keys(this[`_quad${this._curQuad}`]);
}
```

The statement,

```
this[`_quad${this._curQuad}`]
```

creates a reference to one of the local class variables _(Records)_, __quad1_, __quad2_, __quad3_, or __quad4_, depending on the current quadrant number. A _forEach_ function runs the point-circle intersection test against only the circles that lie in the current quadrant,

```
this._check.forEach( (id: string): void =>
{
  circ = this._circleRefs[+id];
  g    = this._circleDO[+id];

  if (TSMT$PointInCircle(this._px, this._py, circ.x, circ.y, circ.radius))
  {
    this._identified.push(circ);
    this._identifiedDO.push(g);

    g.clear();
    g.lineStyle(this.strokeWidth, '0xff0000');
    g.drawCircle(circ.x, circ.y, circ.radius);

    this.onIntersect.emit(id);
  }
```

Note that an Angular _EventEmitter_ is used for the directive to convey an intersection to a containing component (_Pic1Component_). That component in turn executes the _next()_ method of an RxJs _Subject_, which is subscribed to in the main app component (the primary smart component in this application).

Here is a screenshot from one time step of the Canvas-rendered simulation,

![Screenshot of a four quadrant graph. The image is titled "Implementation of the Strategy with Component Lazy Loading in Angular 9. Author: Jim Armstrong, The Algoristmist. Algorithm (1 Render into: Canvas). Total intersections: 8" All over the graph are blue line drawn circles of varying sizes. There are 8 places where the circles cross the X and Y axis. The image is captioned "Simulation Step: 32. © 2020 The Algorithmist."](https://miro.medium.com/max/549/1*BYyUfPIGwGzTNDSMKVMD9g.png)

Note that the quadrant currently containing the test point is highlighted in green. Run the application and change the algorithm id to 2 to see how the SVG simulation display differs.

### **Summary**

This was a long article, but I hope it illustrates how lazy-loaded components can be applied in an actual application. In this hypothetical situation, two different simulations with different algorithms, dependencies, and output are differentiated by an algorithm id. A run-time decision is made as to which simulation to execute. The simulation component and its dependencies are lazy-loaded.

This is in contrast to an alternate scenario where a simulation with identical dependencies and visual display is differentiated by algorithm only. This situation can be handled by a lazy-loaded a computational library instead of a component.

Good luck with your Angular efforts!

---

### **ng-conf: Join us for the Reliable Web Summit**
Come learn from community members and leaders the best ways to build reliable web applications, write quality code, choose scalable architectures, and create effective automated tests. Powered by ng-conf, join us for the Reliable Web Summit this August 26th & 27th, 2021.
<https://reliablewebsummit.com/>