651.288.7000 info@intertech.com

Improving the design, organization, functionality scalability, and maintainability of your Angular application is the key goal of this article.

This collection of tips is intended to provide guidance for new and experienced Angular developers on some common best practices, methodologies, and design practices that will improve the design, organization, functionality, scalability, and maintainability of Angular applications.

The series assumes knowledge of the core concepts of Angular and dives into detail on more complex topics that can help take your applications to the next level.

Angular Application – Tech Brief

by Dave Cloutier

To follow along with the articles there a two repositories created that you will need to access at various points: a starting point and final solution.

Audience

To give some perspective on the intended audience for this series, I can start with a quick review of how this series came to be.  I had an engagement with a client that wanted to move their front end development out of MVC applications and into an Angular / REST API architecture.  I was to develop the initial applications in the roadmap as the clients development team attended an Intertech Angular training course and got up to speed on the framework.  This series was born out of the time working with the developers and aims to address topics that tend to find their way into most applications that I build, but are beyond the scope of an introductory traning courses.  Some topics arose from individual features I used in the applications for the client, and others are more generic tools and techniques that came up in our discussions. My hope is that there is something nearly every level of Angular developer can take away from this series to improve their development in Angular.

Sections

Eleven Detailed Topics Relating To Angular Application Design, Best Practice, & Methodology Challenges

1 – Smart vs. Dumb Components

We start this series with a conversation on architecture.  The number one issue I see with new Angular developers is to equate a page of the application to a single component and include all functionality within the component.  Properly identifying the purpose of a component and understanding how to interact with child components in a maintainable and testable way is something that can greatly improve the code quality of an application.  In this article we take a large component and demonstrate how to break it down into smaller and more re-usable components that better encapsulate functionality.  Click to read…

 

2 – Observables – Keeping Things Clean and Clear

Angular is heavily reliant on the RxJS library which is a library that implements Reactive programming in JavaScript.  While it doesn’t take long at all when learning Angular to run into Observables, they can be one of the toughest concepts for new developers to comprehend, especially when coming from a backround of limited exposure to asynchronous programming. This article discusses some best practices, some opinionated ideas, and pitfalls to be aware of that are not always immediately obvious when working with Observables.  Click to read…

 

3 –The Async Pipe

One of the most common patterns seen in Angular components is to subscribe to an Observable and display the resulting data in a component. When following the patterns described in the first two articles, applications can easily add some bloated boilerplate code. The async pipe is a powerful tool to keep that to a minimum that I have found not all developers get exposed to when learning the framework.  Along with the general use, we dive into some extended functionality of the ngIf directive in conjunction with the async pipe to quickly and easily create effective display components.  Click to read…

 

4 – Content Projection vs. Inputs

Most tutorials and training stick with the simple approach of binding data to components through an input.  This is a simple to implement and effective way to pass data to a child component, however when real life requirements arise such as adding links, images, or other styling, this approach quickly hits limitations. This article aims to show the flexibility and power that comes from content projection opposed to (or often in conjunction with) component inputs.  Click to read…

 

5 – ViewChild and ContentChild

Input, Output, and services are often all that is needed to communicate between components in Angular, however there a times when using these methods do not provide the control and flexibility needed to provide component interaction. ViewChild and ContentChild provide the ability to directly communicate between components and can be extremely powerful when working with tightly related components.  Usage of these tools is often so highly situational that makes providing examples relevant to the situations you will likely face is quite challenging, but awareness of the capability as a whole is often the major hurdle needed to investigate the implementation for a specific need.  Click to read…

 

6 – Dynamic Component Generation

Most Angular components are created by adding a reference directly into a template, however there are times where the type of component won’t be known ahead of time and will need to be dynamically created. Often this is seen with modal windows, application level alerts, or other event driven messages, but could also occur when multiple copies or instances of a component need to be created. In order to create these components you will need to take some extra steps and precautions, but it can open the door to far more advanced functionality in an application.  Click to read…

 

7 – Provider Scopes – Component Level Services

Angular’s developers strongly encourage following the single responsibility principle when creating components and classes. When components grow too large we should turn to services to help separate complex functionality to improve readability, complexity, and testability of an application. However, there are times when the singleton nature of services can provide unexpected results. This article focuses on the ability to control the scope of Angular providers to provide the desired functionality within an application.  Click to read…

 

8 – Control Value Accessor

Forms are a critical component to most any web application. While most forms can be completed with the standard browser inputs, sometimes a more dynamic or thematic input can make the difference in a user interface. Angular provides the ControlValueAccessor interface to provide developers the tools to seamlessly insert custom built components that can function just as a standard input. But as we will see, the ControlValueAccessor can provide much more than just custom inputs – it can serve as a gateway to better form organization and reusability within an application.  Click to read…

 

9 – Reusable Sub-Forms

Angular’s reactive forms are a great way to quickly build complex and robust forms. However, the design tends to force developers to build large components that encompass the entire form and can make it challenging to re-use or nest sub-forms efficiently. By changing the way you think about sections of forms and leveraging ControlValueAccessor, it can become easy to build customizable form sections that can easily be shared between many forms in an application. This article heavily relies upon the information in the Control Value Accessor article, so take the time to review that information first.  Click to read…

 

10 – RouterReuseStrategy – Maintaining Component State on Navigation

Angular provides a powerful built in router to emulate traditional web page navigation and display new components when accessing various URLs within the application.  However, there are times that the default functionality can get in the or cause unexpected results in the application.  There are various ways to work around some of this functionality, but wouldn’t it be great if we could have some control over the router to make some simple decisions that can greatly improve the functionality of our application without overhead?  Let’s look at the RouteReuseStrategy class and find out!  Click to read…
 

11 – Testing Complex Component Interaction

With all the techniques discussed in this series, they open up some challenges from a testing persepective.  With some general understanding of the Angular module functionality, we can replace existing components with mock versions that can greatly simplify testing the interactions that arise using the techniques in this series.  Click to read…

1 – Smart vs. Dumb Components

Smart vs. Dumb Components

Overview

Overall, there are three main tools to use in Angular development, Services, Components, and Directives.  By far the most used throughout an application is the Component – however that does not mean all Components are created equal. 

In the same manner that the class is the basis of all object oriented applications, common design patterns set guidelines and expectations for different types of classes: models, services, repositories, factories, etc.  Each type has a place and an expectation of how it should function in order to keep the structure of an application predictable, maintainable, and testable.  The same mentality can be applied to the Angular Component.  This article focuses on two main types of components, Smart and Dumb components , and how they can be used to build a more scalable, testable, and maintainable application.

A common mistake new Angular developers make is to treat a Component as a page in its entirety.  The Angular router directly maps routes to pages, therefore it is a simple jump mentally to make that Component responsible for all of the content within that page.  While this is generally a good place to start when developing, careful attention should be paid to the Component to continually refactor and break it into smaller chunks.  This helps maintain a key Angular design principal: Components should have a single responsibility. Due to the way the Angular build process works, there is zero overhead during runtime with creating an additional component.  This can be used to our advantage to decouple the application components into smaller, more easily maintained and tested parts.  Enter the smart and dumb component structure. 

 

What Are Smart vs. Dumb Components?

So what are smart and dumb components?  You may hear many different names to refer to them (application, container, or controller vs presentation or pure components), but the idea is the same.  You want components that are responsible for loading and manipulating data to not be intermingled with the presentation and display of that data.

The general guideline is that smart components act as your controller, binding service layer data to your dumb components through Inputs and Outputs.

Smart components have very little display logic, generally only rough framework or items tightly linked to the service layer (e.g. display a spinner while loading, then replace with a data table once data is loaded).  The dumb components are responsible for the layout and interaction with the data (e.g. the data table in the previous example).

Example
To follow along with the articles there a two repositories created: a starting point and final solution.

Let’s take an example large component and break it down into these parts.  Say we have a shopping site with a search page and a list of products matching the search.  We also want to pre-populate the search using query params to allow sharing of search results via URL.  The initial component may look something like the code below.  Note I am using the Bootstrap library to provide some standard styling and display components.  

search.component.ts
@Component({
    selector: 'app-search',
    template: `
        <div class="row">
            <div class="col">
                <form [formGroup]="searchForm" [ngClass]="{'was-validated': attemptSearch}">
                    <div class="form-group">
                        <label for="searchTerm">Search</label>
                        <input type="text" class="form-control" id="searchTerm" formControlName="searchTerm" required />
                    </div>

                    <button class="btn btn-primary" type="submit" (click)="search()">Search</button>
                </form>
            </div>
            <div class="col">
                <ul class="list-group" *ngIf="items">
                    <li class="list-group-item" *ngFor="let item of items">
                        <h2>{{item.name}}</h2>
                        <p>{{item.description}}</p>
                    </li>
                </ul>
                <div *ngIf="searching" class="spinner-border"></div>
            </div>
        </div>`
})
export class SearchComponent implements OnInit {
    public items: ItemInterface[];
    public searching = false;
    public searchForm: FormGroup;
    public attemptSearch: boolean;

    constructor(private formBuilder: FormBuilder, private searchService: SearchService, private route: ActivatedRoute) { }

    ngOnInit() {
        this.attemptSearch = false;
        this.route.queryParams.subscribe(params => {
            this.buildForm(params as SearchInterface);
        });
    }

    private buildForm(init: SearchInterface) {
        this.searchForm = this.formBuilder.group({
            searchTerm: [ init.searchTerm, Validators.required ]
        });
    }

    search() {
        this.attemptSearch = true;
        if (this.searchForm.valid) {
            this.searching = true;
            this.searchService.search(this.searchForm.value).subscribe(data => {
                this.items = data;
                this.searching = false;
            });
        }
    }
}

As you can see this component can start to get fairly large.  This also hasn’t implemented much in the way of display, form validation, or other design elements.  We have a fair amount of coupling between our items, especially from running a search with the query parameters.  Let’s see how we can start to break this apart.

 

Items

First off, let’s start with the display of the items.  We can extract the display logic of the items into it’s own set of components:

 

search-results.component.ts
@Component({
    selector: 'app-search-results',
    template: `
            <ul class="list-group" *ngFor="let item of items">
                <li class="list-group-item">
                    <app-item [item]="item"></app-item>
                </li>
            </ul>`
})
export class SearchResultsComponent {
    @Input() items: ItemInterface[];
}
item.component.ts
@Component({
    selector: 'app-item',
    template: `
        <h2>{{item.name}}</h2>
        <p>{{item.description}}</p>`
})
export class ItemComponent {
    @Input() item: ItemInterface;
}

You can see here we have created two components, one responsible for the display of the individual item and one for handling a list of items.  Take a moment to think about how this design becomes more re-usable (after all, we’ll probably display a item summary somewhere else), and easier to test.  As the item grows and becomes more complex, it’s far simpler to test with an Input than mocking a server response to test corner cases.

This is also a good example to point out that the smart vs. dumb components don’t need to be a 1 to 1 relationship.  If we imagine a shopping cart feature added to this application, the SearchResultsComponent is the ideal place to add in the related service dependency.  It transforms to a smart wrapper component that is aware of the application as a whole and binds together interaction between features.  In this case, selection or actions within the item can be translated to service level actions such as adding or removing from a shopping cart.

 

Search

The next candidate for extraction is the search form.  Search forms can have many complicated internal interactions with field validations, conditional form fields, validation messages, etc.  But ultimately, forms are easily extractable into a black box with a default options input, and a form submission output.  Let’s see how we can accomplish this:

 

search-form.component.ts
@Component({
    selector: 'app-search-form',
    template: `
        <form [formGroup]="searchForm" [ngClass]="{'was-validated': attemptSearch}">
            <div class="form-group">
                <label for="searchTerm">Search</label>
                <input type="text" class="form-control" id="searchTerm" formControlName="searchTerm" required />
            </div>

            <button class="btn btn-primary" type="submit" (click)="search()">Search</button>
        </form>`
})
export class SearchFormComponent implements OnInit {
    @Input() default: SearchInterface;
    @Output() search: EventEmitter<SearchInterface> = new EventEmitter<SearchInterface>();
    public searchForm: FormGroup;
    public attemptSearch: boolean;

    constructor(private formBuilder: FormBuilder) { }

    ngOnInit() {
        this.attemptSearch = false;
        this.searchForm = this.formBuilder.group({
            searchTerm: [ this.default.searchTerm, Validators.required ]
        });
    }

    searchClick() {
        this.attemptSearch = true;
        if (this.searchForm.valid) {
            this.search.emit(this.searchForm.value);
        }
    }
}

Here we have pulled out the search form and provide an Input for default values, and an Output that emits an event containing the search criteria upon a valid search request.  Again, this becomes far more testable and maintainable.  It’s isolated from other functionality, so adding validation and other search fields becomes straightforward and contained within the functionality of the form.  We also get the ability to perform far easier and accurate testing through the Input and Output.  We can directly manipulate the form and test if the search event is emitted, no need for mocking interaction with other services or components.

 

Bringing It Together

Now we can update our initial component to bring all these components together:

 

search.component.ts
@Component({
    selector: 'app-search',
    template: `
        <div class="row">
            <div class="col">
                <app-search-form [default]="init" (search)="search($event)"></app-search-form>
            </div>

            <div class="col">
                <div *ngIf="items">
                    <app-search-results [items]="items"></app-search-results>
                <div>

                <div *ngIf="searching" class="spinner-border"></div>
            </div>
        </div>`
})
export class SearchComponent implements OnInit {
    public init: SearchInterface;
    public items: ItemInterface[];
    public searching = false;

    constructor(private searchService: SearchService, private route: ActivatedRoute) { }

    ngOnInit() {
        this.route.queryParams.subscribe(params => {
            this.init = params as SearchInterface;
        });
    }

    search(criteria: SearchInterface) {
        this.searching = true;
        this.searchService.search(criteria).subscribe(data => {
            this.items = data;
            this.searching = false;
        });
    }
}

As you can see, this component has maintained nearly all of the dependencies and is responsible for understanding where it is in the application.  This is acceptable because we will never re-use this component, it’s responsibility is to be a router endpoint and handle the logic at that specific location.  It also binds the service layer to the actions taken within the application, but has no concern for the implementation of that action.  It doesn’t matter if a selection is made with a button click, a drag-and-drop, gestures, or any other input method.  The dumb components are responsible for translating user actions into an interface that is easy to predict and understand – and also very importantly is already validated.  The smart component is responsible for reacting to those actions however they are made, and triggering actions throughout the application.

Note About Layout
Also of note is how small the template has become for this component. This is a very common side effect of this design pattern.  The smart component is responsible for binding items together and is only responsible for very general layout. 

In a Bootstrap-like grid system, this is generally the best location to put the grid elements for a page as a whole.  This allows for a much easier to see overall application layout. 

Is the page a stacked design with the search on top of the results?  Is it a pinned side bar and scrolling results?  This is not to say the dumb components have no layout responsibility – they are responsible for how that component appears in many situations.  That is to say they should be a responsive design to appear in any of the previously mentioned situations. By having the form component reactive to switch layout of the inputs, it’s easy for the smart component to place it in any of the  various locations and with different set widths (e.g. full width on top, or a narrow pinned side bar).  This separation of responsibility helps maintain a complete plug and play type of architecture and greatly reduces the effort of any redesign. 

 

Smart vs. Dumb Components
Conclusion

There are many more individual situations that can arise, but this design mentality is simple to remember benchmark that will put you on a path to build far simpler to understand, test, and maintain applications.

Next Topic – 2 of 11: Observables – Keeping Things Clean and Clear
2 – Observables: Keeping Things Clean and Clear

Observables: Keeping Things Clean and Clear

Overview

Angular is heavily reliant on the RxJS library which is a library that implements Reactive programming in JavaScript. Reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change (Wikipedia).

The core concept in the RxJS library is the Observable. Observables are streams of data used to inform various parts of the application of a change that may be relevant to that functionality. This article discusses some best practices, some opinionated ideas, and pitfalls to be aware of that are not always immediately obvious when working with Observables.

Review

Let’s start with some review on Observables.  If anything isn’t familiar, I suggest reviewing the Angular Observables documentation for a more thorough overview on the basics of Observables. 

The common use pattern for an Observable is to provide updates as changes happen elsewhere in the application. A prime example of this would be the current user of the application.  A user / authentication service can provide a user Observable that will emit a new value if the user logs out or a new user logs in.  Any part of the application dependent on user settings can react to the change and make the necessary updates.  As a user change could happen through a modal window, it’s a prime example of a change that can occur without any routing or other actions to trigger a change. 

Below is a basic implementation of this concept.

@Component({
    selector: 'app-greeting',
    template: '<div>Hello, {{user.name}}</div>'
})
export class GreetingComponent implements OnInit {
    public user;

    constructor(private userService: UserService) {}

    ngOnInit(): void {
        this.userService.currentUser().subscribe(newUser => this.user = newUser);
    }
}

Clean Up After Yourself

Observables have a potential problem.  Let’s take the example above, what happens when you route to a new page and create a new component?  Every time a user logs in, the new user information is still stored and processed by the GreetingComponent because the subscription is still active.  Now what happens if it’s something with a much larger data set, or more frequent updates?  This is a memory leak that can cause bugs and crashes that are very difficult to trace and predict. 

 

Demonstrating a Leak

We can demonstrate the issue of a memory leak with a few changes to the example above.  First, we can create a dummy service that emits a continual stream of data by emitting a new random name every two seconds:

export interface User {
    name: string;
}
const names: string[] = [
    'Charlie Brown',
    'Darth Vader',
    SNIP...
];

@Injectable({
    providedIn: 'root'
})
export class UserService {
    currentUser(): Observable<User> {
        return interval(2000).pipe(map(this.getRandomUser));
    }

    getRandomUser(): User {
        const index = Math.floor(Math.random() * names.length);
        return {
            name: names[ index ]
        };
    }
}

To see the issue we can add a log statement every time the data changes in the greeting component:

ngOnInit(): void {
    this.userService.currentUser().subscribe(newUser => {
        this.user = newUser;
        console.log(newUser);
    });
}

We can see the data updates in the view and we can see a logged message in the console for each historical value. This is exactly what we would expect, but what happens when we navigate away from the component?  When navigating elsewhere you can see the console messages keep rolling in!

 

 

What is even worse, is if we return to the greeting component it won’t grab the existing stream, it creates a new subscription.  Navigate away and back a few times and you can see the data rolling in at a high speed!

 

 

Avoiding Leaks

To avoid a memory leak, we can unsubscribe the the Observable and stop processing any updates.  There are many articles and methodologies for handling this that you can review to accomplish this, however it can add a fair amount of similar code to every subscription.  There are a few things to keep in mind that can reduce the boilerplate in handling Observables:

    • Limit subscriptions – see section 1 – Smart vs. Dumb Components.  By structuring you app into smart and dumb components, you can reduce the number of subscriptions and convert them to Inputs.  If only your high level controller components need to subscribe then the issue is drastically reduced.

 

    • Use the Async Pipe – the Angular async pipe can be used to subscribe to a promise from the view.  The async pipe handles subscriptions and will unsubscribe for you, so if you only need data in the view then you don’t need to subscribe in the component.

 

  • Use a consistent method – create a reusable component that handles most of the work for you so you don’t need to write the same boilerplate every time.  Create a base class that provides a core that can be used to unsubscribe and provides an Observable that fires and completes in the OnDestroy hook that can be used to unsubscribe when leaving a component.

In order to fix the memory leak, we can implement logic to unsubscribe when destroying a component.  Using the method described in the linked post (without using an abstract class to allow for more clarity), we can create our own short lived Observable that triggers an unsubscribe using the takeUntil method:

export class GreetingComponent implements OnInit, OnDestroy {
    public user;
    public unsubscribe = new Subject<any>();

    constructor(private userService: UserService) { }

    ngOnInit(): void {
        this.userService.currentUser()
            .pipe(takeUntil(this.unsubscribe))
            .subscribe(newUser => {
                this.user = newUser;
                console.log(newUser);
            });
    }

    ngOnDestroy(): void {
        this.unsubscribe.next();
        this.unsubscribe.complete();
    }
}

Now when testing, the logging stops when navigating away and picks back up when we go back to the component.

 

A Problem with Observables

NOTE: This section is completely my opinion, you can find many discussions that argue against this practice with valid points which I will mention, but this has been my findings with my experience using Angular.  The most important concept is to use consistency in an application to semantically communicate expected functionality to improve the quality of code.

Observables represent a continual stream of information.  The have many benefits, including delayed execution – if nobody is subscribed, the action isn’t fired. But let’s take a look at an example that is slightly modified from the one above:

@Component({
    selector: 'app-greeting',
    template: '<div>Hello, {{user.name}}</div>'
})
export class GreetingComponent implements OnInit {
    public user;

    constructor(private userService: UserService) {}

    ngOnInit(): void {
        this.userService.currentUser().subscribe(newUser => this.user = newUser);
        this.userService.getUserPreferences().subscribe(prefs => console.log(prefs));
    }
}

If you look at the code above, you would expect the component to get new user information, and new user preferences when a new user logs in.  However, when running this code you find that the greeting changes, but you never see the new user preferences loaded.  You gnash your teeth and bang your head on the desk looking for the mistake until you finally look at the UserService:

@Injectable()
export class UserService {
    private _user = new BehaivorSubject(null);

    constructor(private authService: AuthService, private http: HttpClient) {}

    currentUser(): Observable<User> {
        return this._user.asObservable();
    }

    login(credentials) {
        if (this.authService.validate(credentials)) {
            this._user.next(credentials.userName);
        }
    }

    getUserPreferences(): Observable<UserPreference> {
        return this.http.get(/api/userPreferences/</span>${<span>this</span>.<span>_user</span>.getValue()}<span>);  } }

While this example is a bit contrived and would be more in depth, the point remains the same.  One observable is updated continually with new information, but one is a single execution http request.  There is nothing about the service API that helps communicate this, so you are left with the need to view the underlying implementation to understand the results.  So the question becomes, can we fix this to help communicate the functionality to any consumer of the service?  The culprit here is the getUserPreferences method, let’s change it:

getUserPreferences(): Promise<UserPreference> {
    return this.http.get(`/api/userPreferences/${this._user.getValue()}`).toPromise(); 
}

NOTE: The toPromise method is being deprecated in future versions of RxJS in lieu of the lastValueFrom function

This is a small change with a big impact.  It clearly helps communicate this is a single value return.  By maintaining this convention of single values use Promises, multiple value streams use Observables we can greatly improve the understanding of underlying implementation with very little loss of functionality or additional code.  There certainly are other improvements that can be made, such as a better name, using a parameter instead of the current user value, etc. that could also help, but the use of a Promise is the single most effective communication tool on the intent of this method.

It now becomes clear how this can and should be consumed in the component:

@Component({
    selector: 'app-greeting',
    template: '<div>Hello, {{user.name}}</div>'
})
export class GreetingComponent implements OnInit {
    public user;

    constructor(private userService: UserService) {}

    ngOnInit(): void {
        this.userService.currentUser().subscribe(newUser => {
            this.user = newUser;
            this.userService.getUserPreferences().then(prefs => console.log(prefs));
        });
    }
}

We know that the Promise is a single return and we want to get that information whenever a user changes, so we can call the method when we need the new information.

We also get a side benefit from this.  As mentioned in the previous section, we need to unsubscribe from Observables.  This isn’t the case for http calls from HttpClient, but how is any consumer of a service supposed to know that?  This convention helps to clearly lay out when Observables need to be unsubscribed and also reduces the need of extraneous unsubscribes when they aren’t necessary.

The downside and counter argument to this approach is Promises have less functionality than Observables, specifically in regards to the pipable functions, and I will agree with that point.  There is certainly an argument for consistently using Observables in an application for this reason and also to reduce the need to learn an addtional API.  Ultimately the decision depends on the application needs, but one thing is true no matter the approach – find a way that works and stick to it consistently.  An application that has a reliable method of communicating functionality – be it naming convention, inference by type, or comments – is a far easier application to understand and maintain.

Observables: Keeping Things Clean and Clear
Conclusion

Observables are a powerful tool that greatly helps Angular applications be reactive and clean – however there are some potential pitfalls with their usage that developers should consider.

Next Topic – 3 of 11: The Async Pipe
3 – The Async Pipe

The Async Pipe

Overview

One of the most common patterns seen in Angular components is to subscribe to an Observable and display the resulting data in a component. As discussed in the Observables – Keeping Things Clean and Clear article, this can add up to some extra boilerplate code in managing the subscriptions and the eventual unsubscribe that is needed. To help cleanly manage these subscriptions, Angular provides the async pipe that can take care of all the overhead for us. Angular also provides some extended functionality of the ngIf directive in conjunction with the async pipe to quickly and easily create effective display components.

To follow along with the articles there a two repositories created: a starting point and final solution.

Without the Async Pipe

To see what the async pipe provides, we will start with an example component that does not use the pipe.  This component calls a service to subscribe to an Observable which it displays directly, an subscriptions that needs modification before display, and a Promise.  First a look at the service:

@Injectable({
    providedIn: 'root'
})
export class SampleService {
    public sampleObservable(): Observable<number> {
        return interval(1000);
    }

    public samplePromise(): Promise<string> {
        return new Promise(resolve => {
            setTimeout(() => resolve('Hello from promise!'), 1500);
        });
    }
}

This service creates an Observable using the interval method.  This fires a counter value every time the interval provided elapses. So by providing 1000 (the parameter is milliseconds), we will get a new counter value every second.  The Promise that is generated is resolved with static text message after a 1500 millisecond timeout.

Now to look at our starting point component:

@Component({
    selector: 'app-manual-subscribe',
    template: `
        <h3>Manual Subscribe Data Load</h3>
        <div>Seconds since subscribe: {{counter}}</div>
        <div>Time at update: {{updateTime | date:'medium'}}</div>
        <div>Promise result: {{message}}</div>`
})
export class ManualSubscribeComponent implements OnInit, OnDestroy {
    public counter: number;
    public message: string;
    public updateTime: Date;
    private unsubscribe = new Subject<void>();

    constructor(private sampleService: SampleService) { }

    ngOnInit(): void {
        this.sampleService.sampleObservable()
            .pipe(takeUntil(this.unsubscribe))
            .subscribe(data => this.counter = data);

        this.sampleService.sampleObservable()
            .pipe(takeUntil(this.unsubscribe))
            .subscribe(() => this.updateTime = new Date());

        this.sampleService.samplePromise()
            .then(data => this.message = data);
    }

    ngOnDestroy(): void {
        this.unsubscribe.next();
        this.unsubscribe.complete();
    }
}

As you can see this is a fairly large component for the limited functionality we are providing due to the necessary boilerplate.  We have two subscriptions in the ngOnInit function – one to bind the new counter value and one to calculate a new date every second to display.  These subscriptions are managed as described in Observables – Keeping Things Clean and Clear by using the takeUntil method that triggers an unsubscribe in ngOnDestroy.  We also bind the result of the promise to a message property to display. Below we can see the results of this component before and after the async methods resolve.

Using the Async Pipe

With this starting point in place, we can bring in the async pipe to help clean everything up for us.  The async pipe is used in a template on any async method or property and Angular will handle the subscription, data binding, and unsubscribe for that reference.  So the first step is to provide a handle to the async objects instead of a static data value.  Below are the changes to the body of the component:

export class AsyncLoadComponent implements OnInit {
    public counter$: Observable<number>;
    public updateTime$: Observable<Date>;
    public message$: Promise<string>;

    constructor(private sampleService: SampleService) { }

    ngOnInit(): void {
        this.counter$ = this.sampleService.sampleObservable();
        this.updateTime$ = this.sampleService.sampleObservable().pipe(map(() => new Date()));
        this.message$ = this.sampleService.samplePromise();
    }
}

There are a few specifics to note about the changes: 

    • ngOnDestroy and the associated unsubscribe subject are gone – Angular handles the unsubscribe for us so we don’t need to worry about it
    •  

    • We declare Observable/Promise properties as a handle to provide the template to the async result.  You may often see async properties with the trailing $ on the variable name as a convention.  This is not required but can be a helpful convention to communicate synchronous vs. asynchronous values
    •  

    • We need to add a map function to the updateTime$ Observable to transform the data instead of transforming in the subscribe.  Here we don’t need the value from the Observable but it is available just as in the subscribe method.  We can pipe any function we want into the Observable stream to modify it before binding including map, filter, debounceTime, etc. 

With these changes, we can implement the async pipe in the template:

<h3>Async Data Load</h3>
<div>Time since subscribe: {{counter$ | async}}</div>
<div>Time at update: {{updateTime$ | async | date:'medium'}}</div>
<div>Promise result: {{message$ | async}}</div>

All that is necessary is to add the async pipe in the data binding and Angular handles the rest.  You can also see in the updateDate$ binding that we can chain pipes to still provide date formatting – just be aware that order matters as data is transformed through the pipes.  The async pipe is also not limited to template binding, but can be used in binding data to child component inputs, directives, or anywhere else that you would normally bind data.  We can test these changes and see that we get the exact same results as our starting point:

Async and NgIf

Often it is desirable to show some loading indicator while we wait for an async value to resolve.  Let’s start with a trimmed down version of the component we created by looking at only an Observable and Promise.  We only want to display the associated text once the first data loads so we need to add some ngIf statements on the wrapper divs to hide them until we have some data:

@Component({
    selector: 'app-async-if',
    template: `
        <h3>Async Data Load With If</h3>
        <div *ngIf="counter$ | async">Time since subscribe: {{counter$ | async}}</div>
        <div *ngIf="message$ | async">Promise result: {{message$ | async}}</div>`
})
export class AsyncIfComponent implements OnInit {
    public counter$: Observable<number>;
    public message$: Promise<string>;

    constructor(private sampleService: SampleService) { }

    ngOnInit(): void {
        this.counter$ = this.sampleService.sampleObservable();
        this.message$ = this.sampleService.samplePromise();
    }
}

If we test, we can see that this works as expected:

However, this approach now means we are managing 4 separate async operations instead of referencing the result twice – once in the ngIf and once in the template data binding.  Here is where Angular provides extra functionality for ngIf to store the results of the conditional statement in a template variable for future use:

<div *ngIf="counter$ | async as result">Time since subscribe: {{result}}</div>
<div *ngIf="message$ | async as result">Promise result: {{result}}</div>
Test Scope: {{result}}

All that is needed is to provide “as <variable>” in the conditional statement to create the binding.  Let’s test this and discuss a few important points to consider:

 

    •  Note that both bindings use the same value which is also used later as a test. The data binding is scoped to within the parent element governed by the ngIf statement.  Best practice would include better results names for the data to prevent confusion, but this is to demonstrate that there are not collisions between these template variables that are created.  Data also does not extend outside of the parent div, so if it is needed in multiple places you will need to place the binding at a higher level or create multiple subscriptions.

 

  • This pattern is also helpful to avoid the need for the safe-navigation-operator (?.) when the resulting value is an object.  The data will only be rendered once the object is defined so we don’t need as much null handling while waiting for data to load.

Finally, we can also implement another helpful ngIf feature by providing an alternative template to display when the data has not yet loaded.  We can do this by creating an ng-template and giving the ngIf directive a reference to the template as the else statement.  The Content Projection vs. Inputs article discusses ng-template in more detail.  Below you can see we create a spinner template that we will show in place of each data element while the data is loading.  Once loaded, we will then show the async results.

<h3>Async Data Load With If</h3>
<div *ngIf="counter$ | async as result else spinner">Time since subscribe: {{result}}</div>
<div *ngIf="message$ | async as result else spinner">Promise result: {{result}}</div>
<ng-template #spinner>
    <div class="spinner-border"></div>
</ng-template>

The Async Pipe
Conclusion

As you can see, the async pipe – especially when coupled with ngIf – can provide a high level of functionality for a common UI pattern with very little code.  The async pipe provides a clean interface, automatically follows best practices, and works very well with other Angular functionality.  While there still are many times in which manually handling subscriptions can be easier or cleaner, you’ll find that the async pipe fits very nicely when using the Smart vs. Dumb Components design pattern.

Next Topic – 4 of 11: Content Projection vs. Inputs

4 – Content Projection vs. Inputs

Content Projection vs. Inputs

Overview

When creating display components, the initial inclination is to reach for the friendly Input on the component. This is an easy to implement and effective method to pass information to a component for display, however it starts to fall short as new requirements arise such as adding links, images, or other styling. This article aims to show the flexibility and power that comes from content projection opposed to (or often in conjunction with) component inputs. 

To follow along with the articles there a two repositories created: a starting point and final solution.

Display Components
In Angular, we often will build display components that can be used to control the presentation of data, inputs, or other elements to the user.  These types of low level components allow for a high level of reuse in the application to give a consistent and maintainable style.  By centralizing content into display components, we can make a change to the CSS for that component and completely update the look and feel of the application in a consistent way.  I have used this with great success in the past for formatting components, or displaying boolean values as icons.  If the format changes, or a new icon is desired, it’s a simple one line change to the application.

For this article, let’s start by building a simple display component: a card.  Cards are simply data displayed within a bordered box to help segregate the content.  Below is a screenshot of a simple usage of this from the Bootstrap documentation.  Let’s take this and make an Angular component!

We want to create a component that will apply the classes for us.  Let’s start with a simple component and populate the body of the card using an Input. 

@Component({
    selector: 'app-input-card',
    template: `
        <div class="card">
            <div class="card-body">
                {{bodyText}}
            </div>
        </div>`
})
export class InputCardComponent {
    @Input() bodyText: string;
}
We can use this component to create the content above like this:
<app-input-card bodyText="This is some text within a card body."></app-input-card>
But cards are often used with a heading.  Below is how we accomplish this with Bootstrap and the resulting display:
<div class="card">
    <div class="card-header">
        A sample card
    </div>
    <div class="card-body">
        This is some text within a card body.
    </div>
</div>


Let’s wrap up the initial design by adding an input for the heading text:

@Component({
    selector: 'app-input-title-card',
    template: `
        <div class="card">
            <h5 class="card-header">
                {{headerText}}
            </h5>
            <div class="card-body">
                {{bodyText}}
            </div>
        </div>`
})
export class InputTitleCardComponent {
    @Input() bodyText: string;
    @Input() headerText: string;
}

Adding Content Projection
This works great for what we currently need and we now have a consistent design element.  However, what happens when the body of the card needs a link, or an image?  How can we better format large sections of text?  With content projection, we can take advantage of content within our component element and place that wherever we need to within our component template.  Let’s first look at how the usage of the component will look once we add content projection before talking about how it is implemented:
<app-project-body-card headerText="A sample card">This is some text within a card body.</app-project-body-card>

As you can see, we no longer have an input for the body.  Instead we use the element as a wrapper around some content.  This let’s us add whatever markup we need to the body.  Below is an example usage and the resulting display.

<app-project-body-card headerText="A sample card">
    Now I <strong>can</strong> add <em>markup!</em >
    <span class="badge badge-info">And Other Elements</span>
</app-project-body-card>

To embed the content, we can use the ng-content element to tell Angular where to place the projected content.  Angular takes the DOM contents from within the component tags and moves them into the template into the ng-content tags.  All we need to do it replace the template interpolation {{bodyText}} with <ng-content></ng-content>.

@Component({
    selector: 'app-project-body-card',
    template: `
        <div class="card">
            <h5 class="card-header">
                {{headerText}}
            </h5>
            <div class="card-body">
                <ng-content></ng-content>
            </div>
        </div>`
})
export class ProjectBodyCardComponent {
    @Input() headerText: string;
}

Multiple Projections
This is great, but we still have the same problem for the heading.  How can we tell Angular to project different content to different places?  Let’s start with how we want this to work and see if we can implement it.  We want to add multiple elements into our element and have Angular put them where they should go.  We’ll need some way to identify where it should go, so let’s add some dummy attributes (header and body) to specify where it should go.  Here is the code and the resulting display:
<app-project-multiple-card>
    <div header>Projected Heading <button class="btn btn-primary">With buttons!</button></div>
    <div body>
        Now I <strong>can</strong> add <em>markup!</em >
        <span class="badge badge-info">And Other Elements</span>
    </div>
</app-project-multiple-card>

This is not exactly what we are looking for, everything is still being inserted into the single <ng-content> tag.  Let’s try adding another tage to see if that helps us split up the values:

@Component({
    selector: 'app-project-multiple-card',
    template: `
        <div class="card">
            <h5 class="card-header">
                <ng-content></ng-content>
            </h5>
            <div class="card-body">
                <ng-content></ng-content>
            </div>
        </div>`
})
export class ProjectMultipleCardComponent { }

Oddly enough, we get the exact same result.  What is happening here?  As I mentioned before, content projection takes DOM content within the element and moves it to the location of the ng-content.  However, when I add two ng-content tags, Angular won’t create DOM elements to duplicate the content – instead the content keeps getting moved around which leaves the first ng-content empty.  This is important to remember when working with projected content, especially if getting into situations where the content is hidden or displayed conditionally with ngIf or display attributes.  Furthermore, the content projection is evaluated before the parent ngIf.  Even if you wrap the ng-content with an ngIf, the content still gets placed before the ngIf executes, and then is removed when ngIf runs. More on dealing with that situation later.

What we need is a way to tell Angular how to pick which content that should go in which location.  To accomplish this, we can use the select directive on the ng-container element.  We can provide any valid CSS selector to use and Angular finds the matching content to project so we will use “[header]” and “[body]” to identify the content based on the dummy attributes that were added earlier.

@Component({
    selector: 'app-project-multiple-card',
    template: `
        <div class="card">
            <h5 class="card-header">
                <ng-content select="[header]"></ng-content>
            </h5>
            <div class="card-body">
                <ng-content select="[body]"></ng-content>
            </div>
        </div>`
})
export class ProjectMultipleCardComponent { }

Success!  We can now move the desired content where we need it to go and we have the ability to add markup to both locations.  This method works great for any predictable structure (for example a input wrapper component that expects a label and an input), but since we are creating arbitrary distinctions, we would be better off implementing a few components or directives.  We will create some components here to demonstrate some further benefits.
@Component({
    selector: 'app-card-heading',
    template: <div [ngClass]="headingClass()"><ng-content></ng-content></div>
})
export class CardHeadingComponent {
    @Input() textStyle: string;

    public headingClass() {
        return `text-${this.textStyle}`;
    }
}

@Component({
    selector: 'app-card-body',
    template: '<ng-content></ng-content>'
})
export class CardBodyComponent { }
A few items to note about these new components. First, the templates both utilize ng-content. We can nest ng-content throughout the elements as needed. The CardBodyComponent doesn’t do much other than give us a declarive way to wrap the content and move it where we need it to go. The CardHeadingComponent has some more going on with it, I’ve added an input that allows control over the styling of the text. This is one of the main reasons to use components to wrap your content – it makes extending functionality far easier and less of a breaking change. All we need to do on our card component is change the select directive to look for these element names. You can see the square brackets are gone because we are looking for an element and not an attribute.
@Component({
    selector: 'app-project-component-card',
    template: `
        <div class="card">
            <h5 class="card-header">
                <ng-content select="app-card-heading"></ng-content>
            </h5>
            <div class="card-body">
                <ng-content select="app-card-body"></ng-content>
            </div>
        </div>`
})
export class ProjectComponentCardComponent { }
And now we can implement this and see the result:
<app-project-component-card>
    <app-card-heading textStyle="primary">
        Projected Heading <button class="btn btn-primary">With buttons!</button>
    </app-card-heading>
    <app-card-body>
        Now I <strong>can</strong> add <em>markup!</em >
        <span class="badge badge-info">And Other Elements</span>
    </app-card-body>
</app-project-component-card>

We still have everything going where we need to go, but we also get the added control of styling our header with an input.

Conditional Projection

Now we can go back to the problem discussed earlier regarding conditional statements associated with the content.  What if we want the option to move the header content to be the footer instead?  This type of situation can arise when creating reactive layouts – we may want our styling to look different on mobile so we need to conditionally make changes to the structure of our content.  For this example I’ll control this through an input on the component, but it could just as easily be an injected service to the component.  In order to place the same content in multiple potential locations, you will need to enlist the help of some other Angular elements: ng-template and ng-container.  We can project the content into a template and use conditional statements to display this where we need it.  So what are ng-template and ng-container, and how are they different than ng-content?

<ng-template>

The Angular ng-template element is based off of the HTML <template> element.  From MDN:

The HTML Content Template (<template>) element is a mechanism for holding HTML that is not to be rendered immediately when a page is loaded but may be instantiated subsequently during runtime using JavaScript.

Think of a template as a content fragment that is being stored for subsequent use in the document. While the parser does process the contents of the <template> element while loading the page, it does so only to ensure that those contents are valid; the element’s contents are not rendered, however.

For Angular’s ng-template, this goes a step further.  If we place content into ng-template, it won’t even be included in the DOM, it gets replaced by a comment – that is until we include a structural directive to tell Angular what to do with the content.

<div *ngIf="!showTemplate else myTemplate">
    I appear when showTemplate is false
</div>

<ng-template #myTemplate>
    I appear when showTemplate is true
</ng-template>

This is an example of a common use case for a template, the else statement of ngIf.  NgIf will render the element it’s on when true, otherwise we can tell Angular to use another template.  This can be an effective way to use a loading animation in place of content while it’s loading, you can use the same template (e.g. a spinner) in place of different sections while the content loads.  The contents can be replicated as needed, so you don’t have any restriction to show one template at a time.

<ng-container>

The Angular ng-container element is another element that doesn’t represent anything in the DOM, but it’s contents are always rendered.  It’s a useful container to use as a wrapper around elements and you have some reason to not use a DOM element such as a div to hold it.  An example usage of this is to address a limitation where you are not allowed to have multiple structural directives on the same element.  Let’s say you want to loop through some elements but only display them if a display property is true.

<!-- This will throw an error and is not valid in Angular -->
<div *ngFor="let item of items" *ngIf="item.display">{{item.text}}</div>

<!-- This is legal and does what we want but does not create any nested elements -->
<div *ngFor="let item of items" >
    <ng-container *ngIf="item.display">{{item.text}}</ng-container>
</div>
We can use the ng-template and ng-container together using the *ngTemplateOutlet structural directive.  This allows us to use the content in a template anywhere we want on the page:
<ng-container *ngTemplateOutlet="template"></ng-container>

<ng-template #template>
    Hello!
</ng-template>

Bringing All Three Together
We can use these tools together to place the heading content into a template, then conditionally display the template in one of two locations determined by the value of the isHeader property. 
@Component({
    selector: 'app-multiple-locations-card',
    template: `
        <ng-template #content>
            <ng-content select="app-card-heading"></ng-content>
        </ng-template>
        <div class="card">
            <h5 class="card-header">
                <ng-container *ngTemplateOutlet="isHeader ? content : null"></ng-container>
            </h5>
            <div class="card-body">
                <ng-content select="app-card-body"></ng-content>
            </div>
            <div class="card-footer">
                <ng-container *ngTemplateOutlet="!isHeader ? content : null"></ng-container>
            </div>
        </div>`
})
export class MultipleLocationsCardComponent {
    @Input() isHeader: boolean;
}
As a side note, this doesn’t still doesn’t give us the opportunity to duplicate the projected content.  If there are two instances of ng-container that display our template, only one will get the content.  This is by Angular design that content projection is never duplicated.

We can now dynamically change the location of where the content goes.  To emulate this, we’ll add a button to toggle a boolean value that we can pass into the input.

<button class="btn btn-info" (click)="contentLocation = !contentLocation">Toggle</button>
<div class="m-3"></div>
<app-multiple-locations-card [isHeader]="contentLocation">
    <app-card-heading>My Title</app-card-heading>
    <app-card-body>Some content</app-card-body>
</app-multiple-locations-card>

Content Projection vs. Inputs
Conclusion

Content Projection is a valuable tool to add to your Angular arsenal.  Not only does it provide useful tools in adding unknown content into a component – it provides the users of that component the most flexibility possible to format the content and include additional elements and functionality to meet their needs.  Once you grasp the associated concepts, you will find a whole new world of possibilites in your code to create more modular and flexible components that can give a significant boost to code maintainability and flexibility.

Next Topic – 5 of 11: ViewChild and ContentChild

5 – ViewChild and ContentChild

ViewChild and ContentChild

Overview

Input, Output, and services are often all that is needed to communicate between components in Angular, however there a times when using these methods do not provide the control and flexibility needed to provide the necessary component interaction. In some cases, especially when components are tightly linked within the same feature (e.g. label / control directives) that direct access to the component or directive class can facilitate the interactivity required. Angular provides the ViewChild / ViewChildren and ContentChild / ContentChildren decorators to facilitate this type of binding and interaction.

This article aims to provide a high level overview of the functionality provided just to give a taste of what is possible.  There are many various ways to use these features and much of that will be left to the imagination and as an exercise to the reader.  Reviewing the Angular documentation on these decorators is a good place to start.  Usage of these tools is often so highly situational that makes providing examples relevant to the situations you will likely face is quite challenging.  Awareness of the capability as a whole is often the major hurdle needed to investigate the implementation for a specific need.

To follow along with the articles there a two repositories created: a starting point and final solution.

Child vs. Children
The ViewChild / ViewChildren decorators and ContentChild / ContentChildren decorators are, as is expected by the similar names, very similar in functionality.  The only notable difference is the Child implementation is relevant to a single reference whereas the Children returns an array of references (specifically a QueryList which is an Angular managed iterable class).  Understanding the Child implementation sets up an easy transition to the Children implementation, so this article will focus on the Child level for ease of understanding and the reduction of complexity.  If your situation calls for multiple references then you can consider the Children implementation.  For this article, I will only refer to ViewChild and ContentChild, but just know that everything applies to it’s associated Children decorator as well.

ViewChild

Selection Types

The ViewChild decorator gives the ability to obtain a reference to an item in the template of a component.  By providing a selector to the decorator, Angular will search for and bind a property on the component to the reference found by the selector.  As mentioned previously, there are many different situations where this can be used.  This is further highlighted by the list of valid selectors that can be used – from the Angular documentation:

The following selectors are supported.

  • Any class with the @Component or @Directive decorator
  •  

  • A template reference variable as a string (e.g. query <my-component #cmp></my-component> with @ViewChild('cmp'))
  •  

  • Any provider defined in the child component tree of the current component (e.g. @ViewChild(SomeService) someService: SomeService)
  •  

  • Any provider defined through a string token (e.g. @ViewChild('someToken') someTokenVal: any)
  •  

  • TemplateRef (e.g. query <ng-template></ng-template> with @ViewChild(TemplateRef) template;)

We will focus on the most commonly used selector, the component selector.

Sample Setup

Let’s set up an example to demonstrate how the decorator is used.  The first thing we need is a child element – for this example we will create a wrapper element for a list group that allows for the selection of some elements:

export interface ListItemInterface {
    display: string;
    isSelected: boolean;
}
@Component({
   selector: 'app-child-list',
   template: `
      <div class="list-group">
         <div
            class="list-group-item list-group-item-action"
            *ngFor="let item of items; let i = index"
            [ngClass]="{'active': item.isSelected}"
            (click)="toggleItem(i)"
         >{{item.display}}</div>
      </div>
      `,
   styles: [`
      .list-group-item-action {
         color: inherit;
      }
   `]
})
export class ChildListComponent implements ListComponent {
   @Input() items: ListItemInterface[];

   public toggleItem(i: number): void {
      this.items[i].isSelected = !this.items[i].isSelected;
   }
}
Now we can also create a component that uses this list and provides some data:
@Component({
    selector: 'app-view-child',
    template: `<app-child-list [items]="items"></app-child-list>`
})
export class ViewChildComponent {
    public items: ListItemInterface[] = [
        {display: 'Apple', isSelected: false},
        {display: 'Orange', isSelected: false},
        {display: 'Banana', isSelected: false},
        {display: 'Kiwi', isSelected: false},
        {display: 'Lemon', isSelected: false}
    ];
}
Here is the result after selecting a few items:


Implementing ViewChild

For the sake of our example, let’s say we want to select items in the list component from outside of the component.  We could use a service to interact with the data, but there are times that may be challenging – for example, what if the list component came from a third party library?  With ViewChild, we can get a reference to the component class and directly interact with the component.  First, we need to add the ViewChild decorator to our parent level component:

export class ViewChildComponent {
   public items: ListItemInterface[] = ..SNIP

   @ViewChild('list') listComponent: ListComponent;
 }
We tell Angular we are looking for an instance of the ChildListComponent by passing the type into the decorator as the selector.  As mentioned earlier, there are many forms the selector can take so review the list from the Angular documents to see the various options.  Angular will search the template for an instance of the component and bind the reference to the listComponent property in the class.

Note: the binding of the ViewChild may be available in the ngOnInit life-cycle hook, but it is not guaranteed and should not be relied upon. Angular provides the ngAfterViewInit life-cycle hook that fires after the ViewChild binding takes place – so any actions that happen during the load of the component should take place here.

We can now interact with any property or method on the instance of the ChildListComponent.  Let’s add a method to remotely select an item and bind that to a list of buttons we create:

@Component({
    selector: 'app-view-child',
    template: `
        <div class="btn-group pb-5">
            <button class="btn btn-secondary"
                *ngFor="let item of items; let i = index" 
                (click)="toggleItem(i)">
                {{item.display}}
            </button>
        </div>
        <app-child-list [items]="items"></app-child-list>`
})
export class ViewChildComponent {
   public items: ListItemInterface[] = ...SNIP

   @ViewChild('list') listComponent: ListComponent;

   public toggleItem(index: number): void {
      this.listComponent.toggleItem(index);
   }
 }
We now have a group of buttons outside of the component we can use to trigger selection via the method inside the component along with still being able to toggle from the list itself:


A Note on Abstraction

The downside of this approach is that we have now created a tight coupling between the two components.  While there are times when the components are so intrinsically linked that this isn’t a problem (e.g. a form group wrapper and a form control).  But when the two components are not so tightly linked, it can be beneficial to use an interface to control what methods are available to other components.  As all methods on a component that need to be accessible to the template must be public, this can create a situation where a method is changed and cause unexpected results throughout the application.  For our example, let’s replace the list implementation with a new component that uses a table instead.

First, we create an interface we can implement with our child components that let us remotely toggle the selected items.

export interface ListComponent {
    toggleItem(index: number): void;
}
Next, in our template we can specify a template variable on the component we aim to select:
<app-child-list [items]="items" #list></app-child-list>
And in the component we can change our ViewChild selector to be more generic:
@ViewChild('list') listComponent: ListComponent;
Instead of a type, we pass in a string of the template variable name.  We also specify the property type to be the newly created interface.  With this we can create a new component that mimics our list but displays values as a table:
@Component({
    selector: 'app-child-table',
    template: `
        <table class="table table-hover">
            <tbody>
            <tr *ngFor="let item of items; let i = index">
                <td [ngClass]="{'bg-success': item.isSelected}" (click)="toggleItem(i)">{{item.display}}</td>
            </tr>
            <tbody>
        </table>
        `
})
export class ChildTableComponent implements ListComponent {
    @Input() items: ListItemInterface[];

    public toggleItem(i: number): void {
        this.items[i].isSelected = !this.items[i].isSelected;
    }
}
All we have to do is change the template in our parent component to the new selector:
<app-child-table [items]="items" #list></app-child-table>

While this is overkill for this situation, it’s a useful pattern to keep in mind to help control interaction between components when directly accessing them.  Where I have really seen this approach shine is in combination with Dynamic Component Generation to create some powerful user interfaces!

ContentChild

Selection Types

ContentChild is similar in function and usage to ViewChild – the major difference is it is used to select elements within the projected content of a component.  If you are not familiar with content projection, see the article: 4 – Content Projection vs. InputsContentChild has some additional restrictions to ViewChild in the types of selectors that can be used.  It only supports Component or Directive types to be used as a selector.

Sample Setup

To demonstrate the usage of ContentChild, we will need to create a few items.  First, a simple directive to use as a selector:

@Directive({
    selector: '[appLabel]'
})
export class ControlLabelDirective { }
Next, a component that uses content projection – this is often some type of wrapper component that expects a specific child structure. We will create a sample form input wrapper where we will eventually add our ContentChild:
@Component({
    selector: 'app-control-formatter',
    template: `<ng-content></ng-content>`
})
export class ControlFormatterComponent { }
Lastly, our parent level template that creates the component. Only the relevant template is shown here:
<app-control-formatter>
    <div class="form-group">
        <label for="exampleInput" appLabel>A field label</label>
        <input type="text" class="form-control" id="exampleInput">
    </div>
</app-control-formatter>
As you can see, our wrapper element sits around a form control group.  This example uses a component but it could just as easily be a directive.

ContentChild Implementation

Our goal is for the wrapper component to implement some formatting on the label element inside of it.  To start, we need to add the ContentChild decorator targeting the ControlLabelDirective we created and applied to the label element:

@Component({
    selector: 'app-control-formatter',
    template: `<ng-content></ng-content>`
})
export class ControlFormatterComponent {
    @ContentChild(ControlLabelDirective) labelRef: ControlLabelDirective;
}
Just as was the case with ViewChild, we don’t have access to this reference in ngOnInit.  Again, Angular gives a life-cycle hook we can use that is fired after the content binding is complete: ngAfterContentInit.  In case you are wondering, this hook occurs after the ngAfterViewInit hook. To add a class to the element, we will inject the Angular Renderer2 class (if you are not familiar with Renderer2see the Angular docs and this article: Angular: Stop Manipulating DOM With ElementRef).  We can then add a class the the element in the ngAfterContentInit life-cycle hook.

@Component({
   selector: 'app-control-formatter',
   template: `<ng-content></ng-content>`
})
export class ControlFormatterComponent implements AfterContentInit {
   @ContentChild(ControlLabelDirective) labelRef: ControlLabelDirective;

   constructor(private renderer: Renderer2) { }

   ngAfterContentInit(): void {
      this.renderer.addClass(this.labelRef.nativeElement, 'text-info');
   }
}
But we have an issue with this code!  Our property is the ControlLabelDirective class, what we actually need to pass to the renderer is the ElementRef for the element.  To address this, Angular provides the ability to pass an options object to the ViewChild and ContentChild decorators.  One of the properties we can pass is the read option.  The read option allows us to direct Angular to bind a different related object type than the directive itself:
@Component({
   selector: 'app-control-formatter',
   template: `<ng-content></ng-content>`
})
export class ControlFormatterComponent implements AfterContentInit {
   @ContentChild(ControlLabelDirective, {read: ElementRef}) labelRef: ElementRef;

   constructor(private renderer: Renderer2) { }

   ngAfterContentInit(): void {
      this.renderer.addClass(this.labelRef.nativeElement, 'text-info');
   }
}
Another example of where the read property is very useful is with ViewChild and using a template variable. For instance, if you have something like the following:
<app-my-component myDirective #myElement></app-my-component>
If you provide the myElement template variable to ViewChild, the read property can be used to distinguish if you are looking for the component or the directive on the element to use for the binding.

We can now test this out and see the results:

As you can see, the ‘text-info’ class has been applied to the label.  As this example shows, ContentChild is often utilized to help control formatting or DOM manipulation when a component or directive expects a specific structure. While this example applies the class at startup, this could easily be extended to change the class based on form validation errors, animations when selecting or interacting with the input, etc.

ViewChild and ContentChild
Conclusion

ViewChild and ContentChild provide an additional way to interact with components in Angular. These tools provide ability for a high level of interaction between a component and it’s children on the DOM tree. While there are dangers in the amount of coupling between components that can be created, careful architecture can help mitigate the issues in future maintenance and is well worth it for the abilities it provides.

Next Topic – 6 of 11: Dynamic Component Generation

6 – Dynamic Component Generation

Dynamic Component Generation

Overview

Most Angular components are created by adding a reference directly into a template, however there are times where the type of component won’t be known ahead of time and will need to be dynamically created. Often this is seen with modal windows, application level alerts, or other event driven messages, but could also occur when multiple copies or instances of a component need to be created. In order to create these components you will need to take some extra steps and precautions, but it can open the door to far more advanced functionality in an application.

To follow along with the articles there a two repositories created: a starting point and final solution.

Sample Environment Setup
In order to dynamically create a component, three items must be prepared.  First, a programmatic trigger is fired that start the process of creating the component.  For our example we will create a form that allows the user to specify the type of component and some options for display and where the component is created.  The code behind this is a simple form that we will interact with via an EventEmitter on the component.  The resulting form looks like the image below and emits an object of the interface shown:

export interface ComponentRequest {
    contextType: 'primary' | 'secondary' | 'success' | 'warning' | 'danger';
    componentType: 'button' | 'alert' ;
    viewPort: number;
}
The next thing we need is a component that we will create.  In this instance we will create two similar components to demonstrate how we can dynamically create different types.  There are more steps needed as part of the setup that will be discussed later, but initially we will just look at the component definition.  We have a ButtonComponent and an AlertComponent – both will display the timestamp of when they are created, take an input for styling, and emit an event to request removal of the component.
@Component({
	selector: 'app-button',
	template: `
		<button class="btn" [ngClass]="getClass()" (click)="remove.emit()">
			Created: {{created | date:'medium'}}
		</button>`
})
export class ButtonComponent implements OnInit {
	@Input() type: 'primary' | 'secondary' | 'success' | 'warning' | 'danger';
	@Output() remove = new EventEmitter<any>();

	public created: Date;

	ngOnInit(): void {
		this.created = new Date();
	}

	getClass(): string {
		return !this.type ? null : `btn-${this.type}`;
	}
}
@Component({
	selector: 'app-alert',
	template: `
		<span class="alert d-flex align-items-center justify-content-between my-2 p-1" [ngClass]="getClass()">
			{{created | date:'medium'}}
			<button type="button" class="close" (click)="remove.emit()">
			  <span aria-hidden="true">×</span>
			</button>
		</span>`
})
export class AlertComponent implements OnInit {
	@Input() type: 'primary' | 'secondary' | 'success' | 'warning' | 'danger';
	@Output() remove = new EventEmitter<any>();

	public created: Date;

	ngOnInit(): void {
		this.created = new Date();
	}

	getClass(): string {
		return !this.type ? null : `badge-${this.type}`;
	}
}
The last item we need is a location where the component should be created.  For this example we will create an array of viewports within which we will create the components.
@Component({
    selector: 'app-dynamic-component-creation',
    template: `
        <div class="row">
            <app-create-request class="col" 
                [viewPorts]="viewPorts" 
                (createComponent)="addToViewport($event)">               
            </app-create-request>
        </div>
        <div class="row card-deck justify-content-between">
            <div class="col-6" *ngFor="let port of viewPorts">
                <div class="card mt-3">
                    <div class="card-header">
                        <h3>View Port #{{port}}</h3>
                    </div>
                    <div class="card-body">
                       <!-- TODO: Components go here -->
                    </div>
                </div>
            </div>
        </div>`
})
export class DynamicComponentCreationComponent{
    public viewPorts: number[] = [1, 2, 3, 4];

    public addToViewport(request: ComponentRequest): void {
        //TODO
    }
}
This component has a location in the template specified within each card body where we want to place the components and has a method bound to the form event to trigger the creation of a component.  Here is what our initial viewports look like:

Prepping for Component Creation

Entry Components

There are two types of components within an Angular application: declarative and entry components.  Declarative components are what you are most used to dealing with – they are generated by declaring a reference to the selector in a template.  Entry components are imperatively loaded by type.  There are two ways in which you previously have interacted with entry components, most likely without knowing it:

  • The root application bootstrapped component – generated during the bootstrap process and loaded into the DOM as the application starts
  • Routed components – dynamically created by the router and loaded into the DOM in the router-outlet

For a component to be declared as an entry component, it must be added to the entryComponents array in the module.  Below is the module definition for our sample where you can see the entryComponents definition:

@NgModule({
    declarations: [
        DynamicComponentCreationComponent,
        CreateRequestComponent,
        ButtonComponent,
        AlertComponent
    ],
    imports: [
        CommonModule,
        FormsModule
    ],
    entryComponents: [
        ButtonComponent,
        AlertComponent
    ],
    exports: [
        DynamicComponentCreationComponent
    ]
})
export class DynamicComponentCreationModule {}
Which begs the question: “I thought you said the app root and routed components are entry components, why don’t we need to declare them here?”  The answer is that you are without knowing it.  Angular automatically adds the bootstrap component and and components in the application routes to the entryComponents array for you.  This is only necessary for components that you dynamically create outside of those situations.

So what exactly is an entry component? For that we can reference the Angular documentation on entry components:

For production apps you want to load the smallest code possible. The code should contain only the classes that you actually need and exclude components that are never used. For this reason, the Angular compiler only generates code for components which are reachable from the entryComponents; This means that adding more references to @NgModule.declarations does not imply that they will necessarily be included in the final bundle.

In fact, many libraries declare and export components you’ll never use. For example, a material design library will export all components because it doesn’t know which ones you will use. However, it is unlikely that you will use them all. For the ones you don’t reference, the tree shaker drops these components from the final code package. If a component isn’t an entry component and isn’t found in a template, the tree shaker will throw it away. So, it’s best to add only the components that are truly entry components to help keep your app as trim as possible.

So when an Angular application is built, Angular will start at all entry components and walk down the template tree to see what is used in order to build the application bundle.

There are some complexities when using entry components in a lazy loaded module that can cause some unexpected headaches. The simplest solution is to declare all entry components in non-lazy loaded modules, however there are workarounds available when needed. For more detail see the related issue #14324

NOTE: With all that being said, the Ivy rendering engine aims to remove the need declaring entry components as this will automatically be handled by the @Component decorator.

ViewContainerRef
The next step in dynamically creating a component is to define a handle to the ViewContainerRef where the component should be inserted.  The most common and easiest way to get a reference to ViewContainerRef is by using ViewChild.  If you are not familiar with ViewChild see the article ViewChild and ContentChild.  In our situation, we have multiple locations so we will use ViewChildren to get a list of generated template references.  First we add the template reference variable to a template where we want to component to go:
SNIP...
<div class="card-body">
    <ng-template #componentTarget></ng-template>
</div>
SNIP..
Next, we can use the ViewChildren decorator to get a reference to the list of #componentTarget templates:
@ViewChildren('componentTarget', {read: ViewContainerRef}) targets: QueryList<ViewContainerRef>;
As you can see we are using the read property to target the ViewContainerRef on the target.

Another pattern is to use a directive. In the directive you can get access to the ViewContainerRef for the directive’s element using dependency injection and then access that through the ViewChild instance.

@Directive({
   selector: '[app-target]',
})
export class AppTargetDirective {
   constructor(public viewContainerRef: ViewContainerRef) { }
}

Creating the Component
We now have everything we need to implement the method to generate the component.  Components are generated using a ComponentFactory instance.  We can easily create on by injecting and using the Angular provider ComponentFactoryResolver.  We can add this to the initialization of our component where we will create the new child components.  Extraneous properties and methods removed for clarity:
export class DynamicComponentCreationComponent implements OnInit {
   private buttonFactory: ComponentFactory<ButtonComponent>;
   private alertFactory: ComponentFactory<AlertComponent>;

   constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

   ngOnInit(): void {
      this.buttonFactory = this.componentFactoryResolver.resolveComponentFactory(ButtonComponent);
      this.alertFactory = this.componentFactoryResolver.resolveComponentFactory(AlertComponent);
   }
}
We now have two handles to ComponentFactories to create the components on demand.  The last step is to create the component in the addToViewport method we stubbed out initially:
private components: ComponentRef<any>[] = [];

public addToViewport(request: ComponentRequest): void {
    const factory = request.componentType === 'button' ? this.buttonFactory : this.alertFactory;
    const target = this.targets.toArray()[request.viewPort];
    const componentRef = target.createComponent(factory);
    componentRef.instance.type = request.contextType;
    componentRef.instance.remove.subscribe(() => componentRef.destroy());
    this.components.push(componentRef);
}

Let’s walk through what is happening here to discuss each step:

 

  1. Create the factory variable to hold the correct factory depending on the data in the request.  This demonstrates how we can programmatically determine which type of component to create.  We can select between as many components as we want as long as the component is defined as an entry component.
  2.  

  3.   Create a target variable to hold the correct ViewContainerRef where the component should go.   Here we are selecting by using the index value passed in by the request object.
  4.  

  5.  Create the component by passing the factory to the ViewContainerRef instance.   The reference to the resulting component is returned from this method so we can access that later to modify the component.
  6.  

  7.  Set input values on the component by interacting with the instance on the ComponentRef handle created in step 3. 
  8.  

  9.  Subscribe to output events using the same instance property.  Here you can see that when the remove event is fired we call the destroy method on the ComponentRef.   This triggers Angular to remove the component from the DOM and fire all the destroy life-cycle hooks.
  10.  

  11.  Keep a reference to all the components we create.   We don’t further interact with them in this example but it is often helpful to keep this reference for further interaction (generally destroying the component from some other interaction).
  12.  

Demonstration
Now that all the parts are in place, let’s test and see how this can work.

Here you can see the components getting created in different locations and styles dynamically, they also function as independent components by tracking the creation time and closing individually.

Dynamic Component Generation
Conclusion

Dynamically creating components is a powerful technique in Angular that can greatly improve the functionality of an application.  A key item to note is that the creation of an item is not limited to a component, services can generate components as long as they are provided a ViewContainerRef to determine where the component should go.  Placing a root level component subscribing to a service is an excellent way to provide global error or notification messages to an application by simply calling a centralized messaging service.

Next Topic – 7 of 11: Provider Scopes & Component Level Services

7 – Provider Scopes & Component Level Services

Provider Scopes & Component Level Services

Overview

Angular’s development team strongly encourages following the single responsibility principle when creating components and classes. When components grow too large we should turn to services to help separate complex functionality to improve readability, complexity, and testability of an application. However, there are times when the singleton nature of services can provide unexpected results. This article focuses on the ability to control the scope of Angular providers to provide the desired functionality within an application.

To follow along with the articles there a two repositories created: a starting point and final solution.

Setup
To demonstrate the situation, we’ll create a sample component that relies upon a service for some of it’s functionality.  This component is a simple card with a button to request a new number and a loading flag to show a spinner while the number is being fetched.  The service generates a random number within a timeout so we have a chance to see the spinner during execution.  Let’s start with the standard approach of creating a root level service to inject:
@Injectable({
   providedIn: 'root'
})
export class LoadingCardService {
   public isLoading = false;
   public randomValueSubject = new BehaviorSubject<number>(null);

   public randomValue(): Observable<number> {
      return this.randomValueSubject.asObservable();
   }

   public runSomething(): void {
      this.isLoading = true;

      setTimeout(() => {
         const randomNumber = Math.floor(Math.random() * 100);
         this.randomValueSubject.next(randomNumber);
         this.isLoading = false;
      }, 2000);
   }
}
And we can then create a component to display the number and a spinner while loading:
<div class="card">
    <div class="card-header">
        <h1>{{type}} Card</h1>
    </div>
    <div class="card-body">
        Your random number is: <span id="random-val">{{loadingCardService.randomValue() | async}}</span>
    </div>
    <div class="card-footer">
        <button id="load-button" class="btn btn-primary" (click)="loadingCardService.runSomething()" [disabled]="loadingCardService.isLoading">
            <span class="spinner-border spinner-border-sm" *ngIf="loadingCardService.isLoading"></span>
            Click Me!
        </button>
    </div>
</div>
@Component({
    selector: 'app-loading-card-global',
    templateUrl: './loading-card.component.html'
})
export class LoadingCardGlobalComponent {
    public type = 'Global';
    constructor(public loadingCardService: LoadingCardService) { }
}
When we create this card, we can see the following functionality:

Dynamic Component Generation
In order to demonstrate the side effects with this approach, we will employ another advanced technique – Dynamic Component Generation.  If you are not familiar with the technique – see the linked article that discusses how Angular can be used to dynamically create and add a component into the DOM.  Below is the wrapper component we are using for this demonstration without commentary on the approach.  Refer to the linked article for more detail and background on this technique.  For the sake of this article, this component is the parent component being used that allows for the generation of multiple instances of our test component.

The situation demonstrated in the article is not limited to dynamically generated components, this would just as easily occur by manually including multiple instances anywhere in the application but dynamic generation is a simpler method to interact with multiple variations of the test component.

@Component({
   selector: 'app-component-scope',
   template: `
        <button class="btn btn-info" (click)="addGlobalCard()">Add Global Card</button>
        <div class="card-group pt-5">
            <ng-template #content></ng-template>
        </div>`
})
export class ComponentScopeComponent {
   @ViewChild('content', { read: ViewContainerRef }) content: ViewContainerRef;

   constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

   addGlobalCard(): void {

      const factory = this.componentFactoryResolver.resolveComponentFactory(type);
      this.content.createComponent(factory);
   }
}

Testing Multiple Instances
Now with the ability to create multiple instances of the component, let’s see what happens:

When clicking the button to generate a value, both cards showed a spinner and the same resulting random number.  This happens because all services are singletons in Angular when injected at the root level.  When an object is created that requests a provider through the constructor, Angular will pass the same instance to all objects that request the provider.  Normally, this is what we want and allows for a single location to store and share data throughout an application and ultimately manage the state of the application.  This default approach is exactly what is expected for something like an authentication service, we wouldn’t want multiple instances that have different users or authentication states. But in this case, the default approach is misleading and could lead to unexpected behavior.

Changing Provider Scope
To address this, Angular gives us the ability to control the scope of a provider.  The great part about this is that it does not require any changes to the service.  As you will see, we can use the same service provided globally, but then use a different version in a subsection of the application.  We can create a new component that uses the same template as the initial test component:
@Component({
    selector: 'app-loading-card',
    templateUrl: './loading-card.component.html',
    providers: [LoadingCardService]
})
export class LoadingCardLocalComponent {
    public type = 'Local';
    constructor(public loadingCardService: LoadingCardService) { }
}
The main difference is the component declares a provider in the decorators.  When Angular’s dependency injection looks for an instace of a provider to inject, it does so starting from the component and working its way up the component tree all the way to the root of the application.  This is why services are generally given the “providedIn: ‘root'” decorator – it is shorthand to tell Angular to provide it in the root application module.  What is important to note here is that we are not limited to defining the provider just at the consuming component.  This allows us to set the scope of a service to a module or a parent component and gives a great deal of flexibility to easily control what is injected where.

To test this, I’ll add the option to create cards of both types in our home component:

@Component({
   selector: 'app-component-scope',
   template: `
   <button class="btn btn-info" (click)="addGlobalCard()">Add Global Card</button>
   <button class="btn btn-info" (click)="addLocalCard()">Add Local Card</button>
      <div class="card-group pt-5">
         <ng-template #content></ng-template>
      </div>`
})
export class ComponentScopeComponent {
   @ViewChild('content', { read: ViewContainerRef }) content: ViewContainerRef;

   constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

   addGlobalCard(): void {
      this.addCard(LoadingCardGlobalComponent);
   }

   addLocalCard(): void {
      this.addCard(LoadingCardLocalComponent);
   }

   addCard(type: Type<unknown>): void {
      const factory = this.componentFactoryResolver.resolveComponentFactory(type);
      this.content.createComponent(factory);
   }
}
Let’s create two components of each type and see it in action:

Now, when clicking a single load button on a globally scoped service component we can see all the global components react and start loading as before and also load the same random value from the service as before – however the components with a locally scoped service remain in the initial state. when clicking the load button on one of those services it will load separately and create a different random number.  The other locally scoped component still remains in the initial state. 

You can see how with a single change we can control how data is shared and controlled in the application.  Our global cards are bound together and work off the same set of data, the local cards have their own service instance and don’t share data with each other. 

Child Component Dependency Injection
But what happens with child components?  Let’s pull the button out into it’s own component and find out:
@Component({
    selector: 'app-loading-button',
    template: `
    <button id="load-button" class="btn btn-primary" (click)="loadingCardService.runSomething()" [disabled]="loadingCardService.isLoading">
        <span class="spinner-border spinner-border-sm" *ngIf="loadingCardService.isLoading"></span>
        Click Me!
    </button>`
})
export class LoadingButtonComponent {
    constructor(public loadingCardService: LoadingCardService) { }
}
And our test component’s template changes:
SNIP...
<div class="card-footer">
    <app-loading-button></app-loading-button>
</div>
SNIP...
And finally we can test again and see we get the exact same behaivor:

The buttons are still bound to the isLoading value for the instance of the provider that comes from the parent component.  Remember, Angular walks up the component tree to find the lowest level provider to inject so the button will find the service scope at the global or local level depending on the setup of the parent. This means you can alter the provider at any level of an application – a module, a route component, down the the smallest display component and alter the behavior for any children.

Testing Notes
There is an important point to take notice of from a testing perspective.  The rule of how Angular selects the instance to inject works the same in the TestBed.  Therefore, you can no longer just declare a provider in the configureTestingModule method – this is the same as declaring a service at the root level.  When the TestBed creates the test component, the component level declaration will take over and the actual service class will be injected, not the mock defined in the test.  Let’s create a test and see this in action – below is the test we will use for both types of components and it will simply mock the randomValue() method to return 5 and check the template for the value:
describe('LoadingCardGlobalComponent', () => {
    let component: LoadingCardGlobalComponent;
    let fixture: ComponentFixture<LoadingCardGlobalComponent>;
    let loadingCardService: jasmine.SpyObj<LoadingCardService>;

    beforeEach(() => {
        loadingCardService = jasmine.createSpyObj(['runSomething', 'randomValue']);
        loadingCardService.randomValue.and.returnValue(of(5));

        TestBed.configureTestingModule({
            declarations: [LoadingCardGlobalComponent, LoadingButtonComponent],
            providers: [
                { provide: LoadingCardService, useValue: loadingCardService }
            ],
            schemas: [NO_ERRORS_SCHEMA]
        }).compileComponents();
        fixture = TestBed.createComponent(LoadingCardGlobalComponent);
        component = fixture.componentInstance;

        fixture.detectChanges();
    });

    it('should create the component', () => {
        expect(component).toBeTruthy();
    });

    it('should show the random number', () => {
        const valElement = fixture.debugElement.query(By.css('#random-val')).nativeElement;
        expect(valElement.innerText).toContain(5);
    });
});
When these are executed we get a failure saying that the random number span is empty and not 5.

We don’t see an injection error, we just aren’t seeing the mock value because an actual instance of the service is being used.  The creation of the component is lower in the tree than the TestBed module, so that takes precedence.  What needs to be done is to override the component level definition:

SNIP...

beforeEach(() => {

   loadingCardService = jasmine.createSpyObj(['runSomething', 'randomValue']);
   loadingCardService.randomValue.and.returnValue(of(5));

   TestBed.configureTestingModule({
      declarations: [LoadingCardLocalComponent],
      providers: [
         { provide: LoadingCardService, useValue: loadingCardService }
      ],
      schemas: [NO_ERRORS_SCHEMA]
   });

   TestBed.overrideComponent(LoadingCardLocalComponent, {
      set: {
         providers: [
            { provide: LoadingCardService, useValue: loadingCardService }
         ]
      }
   });

   TestBed.compileComponents();
   fixture = TestBed.createComponent(LoadingCardLocalComponent);
   component = fixture.componentInstance;

   fixture.detectChanges();
});

SNIP...
The overrideComponent method let’s us change the decorator on the component.  Just note that this has to be done prior to calling compileComponents() or createComponent()!

Now the test is using the mock service we as we expect it to.

Provider Scopes & Component Level Services
Conclusion

It is important to note what has been demonstrated works for any provider, not just services.  Take a moment to consider the many possibilities this can open up for creating re-usable and truly dynamic components in Angular.  Pulling default values or configuration options into injected providers gives users much more control over components and how they function.  There are many options that generally get added as Input properties that can make far more sense as providers – which can also help to greatly clean up templates and overall application organization by allowing you to build components that far better follow SOLID design.  It also provides a way to give a simple to implement, high level way to control of data sharing within the application.

Next Topic – 8 of 11: Control Value Accessor

8 – Control Value Accessor

Control Value Accessor

Overview

Forms are a critical component to most any web application. While most forms can be completed with the standard browser inputs, sometimes a more dynamic or thematic input can make the difference in a user interface. Angular provides the ControlValueAccessor interface to provide developers the tools to seamlessly insert custom built components that can function just as a standard input. But as we will see, the ControlValueAccessor can provide much more than just custom inputs – it can serve as a gateway to better form organization and reusability within an application.

To follow along with the articles there a two repositories created: a starting point and final solution.

A Rating Input Component
Let’s start by creating a component that we want to function as a custom form input.  In this example, we will build a rating input that allows a user to select a value from 0 to a maximum rating by clicking a star.  We can use the FontAwesome library to get the star icons and change between empty and filled versions.  Below is the starting point for the component:
class RatingStar {
    icon: IconDefinition;
    index: number;
    selected: boolean;

    constructor(index: number, rating: number) {
        this.index = index;
        this.selected = index < rating;
        this.icon = this.selected ? faStarSolid : faStarEmpty;
    }
}

@Component({
    selector: 'app-rating-control',
    template:  <br /></span><span>      <div> <br /></span><span>         <fa-icon *ngFor="let star of ratingStars; let i = index"<br /></span><span>                size="lg"  <br /></span><span>                [icon]="star.icon"<br /></span><span>                [ngClass]="{'selected': star.selected}" <br /></span><span>                (click)="setRating(i)" > <br /></span><span>         </fa-icon> <br /></span><span>      </div>,
    styles: [  fa-icon { cursor: pointer; } .selected { color: GoldenRod; } ]
})
export class RatingControlComponent implements OnChanges {
    @Input() maxRating = 10;
    @Input() rating = 0;
    @Output() ratingChange = new EventEmitter<number>();
    public ratingStars: RatingStar[] = [];

    ngOnChanges(): void { this.calculateRating(); }

    private calculateRating(): void {
        this.ratingStars = [];
        for (let i = 0; i < this.maxRating; i++) { this.ratingStars.push(new RatingStar(i, this.rating)); }
    }

    setRating(index: number): void {
        this.rating = index + 1;
        this.calculateRating();
        this.ratingChange.emit(this.rating);
    }
}

The high level overview of this component is:

 

  1. It uses an array of a RatingStar class that is used to determine which icon to show for a given star
  2.  

  3. The rating array is recalculated whenever an input changes or the user clicks on a star 
  4.  

  5. The user’s click on a star also emits the new value to enable two way data binding

 

The resulting component is used in a parent component bound to a max rating input and displays the output rating value to verify functionality.

Implementing ControlValueAccessor

Using the Component without ControlValueAccessor

We have a component that gives us some data, let’s see if we can use it in a form.  Below is the form test bed we will use for testing, it includes the following features:

  1. A native input for comparison to the custom control we are building
  2. The custom rating control – note that the two way binding to rating is no longer included or needed
  3. Default values for each control
  4. Options to enable or disable the entire form
  5. A button to reset the state of the form
  6. Output of the form value and touched status
@Component({
    selector: 'app-control-value-accessor',
    template: <br /></span><span>        <form [formGroup]="testForm" autocomplete="off" class="w-25 was-validated"><br /></span><span>            <div class="form-group"><br /></span><span>                <label>Test Input</label><br /></span><span>                <input class="form-control" type="text" formControlName="testInput"><br /></span><span>            </div><br /></span><span><br /></span><span>            <div class="form-group"><br /></span><span>                <label>Rating</label><br /></span><span>                <app-rating-control [maxRating]="5" formControlName="rating"></app-rating-control><br /></span><span>            </div><br /></span><span>        </form><br /></span><span>        <button class="btn btn-secondary" (click)="testForm.disable()">Disable Form</button><br /></span><span>        <button class="btn btn-success" (click)="testForm.enable()">Enable Form</button><br /></span><span>        <button class="btn btn-danger" (click)="testForm.reset()">Reset Form</button><br /></span><span>        <div style="white-space: pre"><br /></span><span>            {{testForm.value | json}}<br/><br /></span><span>            Touched: {{testForm.touched | json}}<br/><br /></span><span>            Valid: {{testForm.valid}}<br/><br /></span><span>            Errors: {{testForm.controls['rating']?.errors | json}}<br/><br /></span><span>        </div>
})
export class ControlValueAccessorComponent implements OnInit {
    public testForm: FormGroup;

    constructor(private formBuilder: FormBuilder) { }

    ngOnInit(): void { this.testForm = this.formBuilder.group({ testInput: 'abc', rating: 3 }); }
}
When we open this page the following error appears in the console:

The error specifies that for the element we specified as the ‘rating’ form control, Angular isn’t able to find a value accessor to know how to interact with the component.  So what exactly is a value accessor?

The ControlValueAccessor Interface

ControlValueAccessor is an interface than Angular uses to keep the view in sync with forms data models and vice-versa.  There are 4 methods on the interface, one of which is optional.  We will walk through each method to better understand how Angular handles forms under the hood:

interface ControlValueAccessor {
    writeValue(obj: any): void
    registerOnChange(fn: any): void
    registerOnTouched(fn: any): void
    setDisabledState(isDisabled: boolean)?: void
}

WriteValue

The writeValue method is responsible for updating the view when there are programmatic changes to the form.  In the example of our rating component, this would be when the Input value changes for the rating and we need to recalculate which stars are shown.

RegisterOnChange

The registerOnChange method is called at the initialization of the form and registers a callback function to notify Angular when our control view has changed and the data needs to propagate to the form data model.  The parameter of this method is a function that the control will need to save the reference and then call at the appropriate times.  In our example, this should fire whenever a user clicks a star.

RegisterOnTouch

The registerOnTouch method is similar to the registerOnChange method as it also registers a callback function.  This function is to notify the forms data model that the control has been touched.  In a standard input, this is the blur event when a user clicks or tabs into the input but has not yet made a change.  In our example, there is no blur method so we won’t have anything to implement.  This is not uncommon and the touched property will get updated along with the change callback.

SetDisabledState

The setDisabledState method is an optional method for the interface.  The method receives a boolean parameter that specifies if the control should be disabled or enabled.  This is used to set the appropriate styling on the component to signify the state.

Implementing ControValueAccessor on a Component

There are two necessary steps to set a component to serve as a form value accessor, we must implement the ControlValueAccessor interface and also identify the component as a control value provider.

Step 1 – Interface Implementation

We can implement each interface method one by one to see how they function.

Write Value

To implement writeValue we will need a way to store the current value of the control within the component.  We can use the rating property, but we no longer need to set it as an input to the control.  When writeValue is called, we should set the rating to the provided value and update the view:

public rating: number;

writeValue(obj: any): void {
    this.rating = obj;
    this.calculateRating();
}
RegisterOnChange

To implement registerOnChange we need a property to save a handle to the function provided.  This method can replace the ratingChange event we had implemented as it serves the same exact purpose.  All we need to do is save the method passed into the function and call it with the new value every time the control changes:

public onChangeFn;

setRating(index: number): void {
   this.rating = index + 1;
   this.calculateRating();
   this.onChangeFn(this.rating);
}
registerOnChange(fn: any): void { this.onChangeFn = fn; }

RegisterOnTouched

We could leave registerOnTouched as an empty function as we don’t really have a touch event for the form control.  However, for demonstration we can consider the control touched when the user hovers over the rating.  All we need to do is call the method whenever the mouseleave event occurs on the wrapping element:

template: `<div (mouseleave)="onTouchFn()">
             <fa-icon ...></fa-icon>
           </div>`

SNIP...
public onTouchFn;

registerOnTouched(fn: any): void {
    this.onTouchFn = fn;
}
SetDisabledState

The setDisabledState method is optional, but we can fairly easily implement it for this control.  All we need to do is apply some styling to gray out the control and prevent the user click’s from changing the value.  First – in the component we need to track if the control is disabled and make a change to setRating to stop any changes from happening when disabled:

public isDisabled: boolean;

setRating(index: number): void {
    if (!this.isDisabled) {
        this.rating = index + 1;
        this.calculateRating();
        this.onChangeFn(this.rating);
    }
}

setDisabledState?(isDisabled: boolean): void {
    this.isDisabled = isDisabled;
}
And create a new CSS class – the entire component styling is included for context:
fa-icon {
    cursor: pointer;
}
.selected {
    color: GoldenRod;
}

.disabled {
    color: gray !important;
    cursor: default;
}
Lastly – we apply the disabled class to the icons when disabled:
<fa-icon ...SNIP... [ngClass]="{'selected': star.selected, 'disabled': isDisabled}"></fa-icon>

Step 2 – Control Provider

Even with the ControlValueAccessor interface implementation we still get the same error as before when testing the form.  The reason is that once the code is compiled, Angular has no way to identify that a component implements an interface.  Instead, we need to register the component as a provider so Angular can easily obtain a reference to the class it will use to communicate with the form view.  To do so, we can add a provider to the RatingControlComponent:

providers: [
    {
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => RatingControlComponent),
        multi: true
    }
]
NG_VALUE_ACCESSOR is the token Angular uses to get the ControlValueAccessor implementations in the application.  If you have not seen forwardRef before, it simply allows us to refer to an item that is declared but not yet created.  We also need to use the multi option – in short this adds the binding to an array of items to be injected instead of overriding a single value. 

Testing The Form
With our custom control set up we can now test the form and make sure everything works.  Our test form contains the JSON data of the form model itself and the value of the touched flag:

You can see the touched value get updated when the cursor leaves the component, data is bound to the form just like the native input, the disabled status is applied, and the control resets with the form reset command. In summary, the custom control acts just as the native input and there is no difference from the form’s perspective on how to interact with the control.

Control Validation
When talking about forms, we must always consider validation as well.  There are two avenues of validation to consider with custom elements – control defined and user defined.

Control Defined Validation

Custom controls may have internal validation that is always active – for example a date picker control may validate that the input is a valid date.  For this example we can implement a minimum rating option that we define as an input to the component. To prepare we can add an input to the component to

@Input() minRating = 3;
We will also add a control to change the value of the minimum rating.  Take note that this is outside of the form we have defined, so any changes to this data value will not trigger any changes to the form on it’s own.  Below is a highlight of the relevant changes:
<form [formGroup]="testForm">
    <app-rating-control [maxRating]="5" [minRating]="minRating" formControlName="rating"></app-rating-control>
</form>

SNIP...
<div class="form-group">
    <label>Min Rating</label>
    <input name="minRating" class="form-control" type="number" [(ngModel)]="minRating">
</div>

// In Component default the value
public minRating = 3;
For our custom control to communicate to the Angular forms API that it is invalid we need to implement the Validator interface.   There are two methods in this interface, one of which is optional.

Validate

The required method to implement is the validate method.  It provides the control as a parameter (as an AbstractControl) to the method and expects a null (valid) or a key-value pair (invalid) result.  This signature is very similar to implementing any custom form validator.  For our example, we just want to make sure that the value is above or equal to the minimum rating:

validate(control: AbstractControl): ValidationErrors {
    return control.value >= this.minRating ? null : { tooLow: 'It\'s not that bad...'};
}

RegisterOnValidatorChange

The registerOnValidatorChange method is optional and registers a callback to call whenever the logic to determine if the control is valid changes.  If the validation is a static check then this is not required.  Going back to the date picker example we would only want Angular to check the validation whenever the control value changed.  In our example, a change from outside the form (the minRating input value) could impact the valid status of the control so we want to execute the callback to trigger Angular to recheck the control.  It’s sufficient for this control to just put the callback in the ngOnChanges method.

public onValidatorChangeFn;

registerOnValidatorChange?(fn: () => void): void {
    this.onValidatorChangeFn = fn;
}
ngOnChanges(): void {
    this.calculateRating();
    if (this.onValidatorChangeFn) {
        this.onValidatorChangeFn();
    }
}
Notice the check on the function.  This is generally required as the registration of the callback happens after the initial setting of the input values which would throw an error when creating the component.  Angular runs an initial validation check on form creation so we only need to be concerned with changes after the callback is registered.

Provider Registration

We also need to register the component as a Validator, this is nearly identical to the process for ControlValueAccessor just using a different token:

providers: [
    {
        provide: NG_VALUE_ACCESSOR,
        useExisting: forwardRef(() => RatingControlComponent),
        multi: true
    },
    {
        provide: NG_VALIDATORS,
        useExisting: forwardRef(() => RatingControlComponent),
        multi: true
    }
]

User Defined Validation

Custom controls can have validation also applied the way you would for any other input.  Here we can make the rating required so we can see how the two methods of validation interact:

this.testForm = this.formBuilder.group({
    testInput: 'abc',
    rating: [3, Validators.required]
});

Visualizing Status

We want to be able to see when the component is invalid, so we can add some simple CSS to the form component to change the stars to red when invalid.  Angular applies a ng-invalid class to controls automatically when they are not valid that we can utilize:

app-rating-control.ng-invalid {
    color: red;
}
We can also add some data binding to the sample form to see the status and any errors on our control:
Valid: {{testForm.valid}}<br/>
Errors: {{testForm.controls['rating'].errors | json}}<br/>

Testing Validation

With this in place, we can test the validation and see how the control reacts.

We can see that when the rating goes below the minimum the control is invalid. Also, when it is reset the required error is triggered and the control is also invalid.  There is no difference between the two methods for how the control displays as both will add the ng-invalid class to be used for styling.

Control Value Accessor
Conclusion

Getting comfortable with ControlValueAccessor can significantly increase your ability to create unique and relevant ways for users to interact with your application.  As we will see in the next article – Reusable Sub-Forms – we can leverage this functionality for groups of fields as well.  It is an excellent way to isolate the complex issues that can arise in a complicated control from the implementation in a form.

Next Topic – 9 of 11: Reusable Sub-Forms
9 – Reusable Sub-Forms

Reuseable Sub-Forms

Overview

Angular’s reactive forms are a great way to quickly build complex and robust forms. However, the design tends to force developers to build large components that encompass the entire form and can make it challenging to re-use or nest sub-forms efficiently. By changing the way you think about sections of forms and leveraging ControlValueAccessor, it can become easy to build customizable form sections that can be shared between many forms in an application. This article heavily relies upon the information in the Control Value Accessor article, so take the time to review that information first.

To follow along with the articles there a two repositories created: a starting point and final solution.

Use Case
In many applications, there are often sets of fields that appear across many different forms.  For example, an e-commerce application may have address fields appear in user registration, billing information, shipping information, etc.  For this example, we will create a sub-form of user information that we can add into the testing form created in the Control Value Accessor article.

To begin, we can create a component that will represent our sub form.  We want the form to have three inputs: first name, last name, and email address.  We will implement some validation by requiring the last name and validating the email address pattern.  I have added some validation styling using Bootstrap to help clearly show the status of the controls at all times:

@Component({
   selector: 'app-user-form',
   template: `
        <form [formGroup]="userForm" class="was-validated">
            <div class="form-group">
                <label for="firstName">First Name</label>
                <input id="firstName" type="text" class="form-control" formControlName="firstName">
            </div>
            <div class="form-group">
                <label for="lastName">Last Name</label>
                <input id="lastName" type="text" class="form-control" formControlName="lastName" required>
                <div class="invalid-feedback">
                    Last Name is required
                </div>
            </div>
            <div class="form-group">
                <label for="email">Email</label>
                <input id="email" type="email" class="form-control" formControlName="email">
                <div class="invalid-feedback">
                    Not a valid email address
                </div>
            </div>
        </form>
    `
})
export class UserFormComponent implements OnInit {
    public userForm: FormGroup;

    constructor(private formBuilder: FormBuilder) { }
    ngOnInit(): void {
        this.userForm = this.formBuilder.group({
            firstName: null,
            lastName: [null, Validators.required],
            email: [null, Validators.email]
        });
    }
}
Here is the resulting form showing the validation checks are working for both fields:

Making It Reusable with ControlValueAccessor
ControlValueAccessor is not just limited to single value controls, we can use it to return objects of data.  As long as the ControlValueAccessor interface is implemented we can use any method we want to manipulate and display the data, so why not another form?  Let’s do this!

Implement ControlValueAccessor

Just as with a single value control, we can implement ControlValueAccessor for our sub-form.  The forms API makes some of this quite easy to implement, the relevant changes are show below:

Template

<ng-container [formGroup]="userForm">
    <input id="firstName" type="text" class="form-control" formControlName="firstName" (blur)="formTouchFn()">
    <input id="lastName" type="text" class="form-control" formControlName="lastName" required (blur)="formTouchFn()">
    <input id="email" type="email" class="form-control" formControlName="email" (blur)="formTouchFn()">
</ng-container>
Component
public formTouchFn;

constructor(private formBuilder: FormBuilder, private ngForm: FormGroupDirective) { }

writeValue(obj: any): void {

    const emtptyForm = {
        firstName: null,
        lastName: null,
        email: null
    };

    const data = Object.assign(emtptyForm, obj);
    this.userForm.patchValue(data);
}

registerOnChange(fn: any): void {
    this.userForm.valueChanges.subscribe(fn);
}

registerOnTouched(fn: any): void {
    this.formTouchFn = fn;
}

setDisabledState?(isDisabled: boolean): void {
    if (isDisabled) {
        this.userForm.disable();
    } else {
        this.userForm.enable();
    }
}
  • writeValue – there is some extra considerations to take here besides just setting the value.  There are two methods available to us for setting the value of a form, setValue and patchValue.  They work in a similar manner with the distinction that setValue expects a mapping for every property in the form whereas patchValue ignores any non-matching values.  Each can successfully be used here, but you’ll need to be aware of the consequences of each choice.  The other consideration is handling a null parameter to writeValue – which is exactly what happens when using the reset form method.  In the code above that is using patch value, passing null will not clear the existing values as every control is skipped.  By merging with an empty object we can ensure that the control value is cleared when writeValue is not given a property for the control.
  • registerOnChange – forms have an Observable that is fired every time a change is made to the form, all we need to do is bind the callback to the Observable callback.  Easy!
  • registerOnTouched – this is unfortunately not a simple as registerOnChange because there is nothing Angular provides to subscribe to touch events in a form (at least until #10887 is addressed).  The best option is to bind the callback to the blur event for each input in order for the touch to cascade up the form properly.  If your application doesn’t rely on the form level touched then this can generally be omitted.
  • setDisabledState – we can leverage the disable and enable methods on the form that will cascade the disabled value down the line for us
  • form – note that the wrapper element around the form is no longer a form tag.  You can see unexpected results when nesting form elements so it is good practice to leave the form definition for the high level forms only.  If you need access to the form element (e.g. if using the submitted state) you can access it for the consuming form by injecting FormGroupDirective into the sub-form as shown in the constructor.
  • Implement Validator

    We also want any validation errors on our form to propagate to the consuming parent level form.  In order to do this, we need to implement the Validator interface.

    validate(control: AbstractControl): ValidationErrors {
        return this.userForm.valid ? null : { invalidForm: { valid: false, errors: this.userForm.errors } };
    }
    
    registerOnValidatorChange?(fn: () => void): void { }
    validate – returns an object when the form is not valid.  Note – errors do not roll up in Angular, so only form level errors are displayed here.  If you want to see all errors for all controls you can implement something that loops through them all like the following:
    validate(control: AbstractControl): ValidationErrors {
        const form = this.userForm;
        if (form.valid) {
            return null;
        }
        const errors = {};
        Object.keys(form.controls).forEach(k => {
            if (form.controls[k].invalid) {
                errors[k] = form.controls[k].errors;
            }
        });
    
        return errors;
    }
    registerOnValidatorChange – as the validators never change for this form we don’t need to implement anything.  If validators were determined by component inputs, we would just need to call the callback function in ngOnChanges.

    Register Providers

    Lastly – we just need to register the component as a value accessor and validator provider:

    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => UserFormComponent),
            multi: true
        },
        {
            provide: NG_VALIDATORS,
            useExisting: forwardRef(() => UserFormComponent),
            multi: true
        }
    ]

    Testing The Form
    To test the form, all we need to do is add it to an existing form like any other control:
    // In Template
    <app-user-form formControlName="user"></app-user-form>
    
    // In Component
    this.testForm = this.formBuilder.group({
        testInput: 'abc',
        rating: [3, Validators.required],
        user: {firstName: 'Steve', email: 'steve@test.com'}
    });
    The sub form appears and is pre-loaded with the default values specified and ready to test:

    The sub form works as expected to populate the user data, validation on the individual controls in the sub form carry to the parent form validity, and all controls follow the disabled and reset commands just as the native input on the parent level of the form.

    Reusable Sub-Forms
    Conclusion

    ControlValueAccessor is a powerful tool to extend Angular forms and design compact and re-usable forms.  In applications that have many re-usable forms, extracting an abstract base class to provide a default ControlValueAccessor implementation is fairly trivial and can make for extremely fast development of contained and re-usable form elements that interact seamlessly with parent forms.

    Next Topic – 10 of 11: RouteReuseStrategy – Maintaining Component State on Navigation

    10 – RouteReuseStrategy – Maintaining Component State on Navigation

    Reuseable Sub-Forms

    Overview

    Angular provides a powerful built in router to emulate traditional web page navigation and display new components when accessing various URLs within the application.  However, there are times that the default functionality can get in the way or cause unexpected results in the application.  There are various ways to work around some of this functionality, but wouldn’t it be great if we could have some control over the router to make some simple decisions that can greatly improve the functionality of our application without overhead?  Let’s look at the RouteReuseStrategy class and find out!

    To follow along with the articles there a two repositories created: a starting point and final solution.

    RouteReuseStrategy
    Angular provides an abstract class called RouteReuseStrategy that controls how and when components are created, saved, and destroyed during routing.  By default, Angular uses the DefaultRouteReuseStrategy class below:
    export class DefaultRouteReuseStrategy implements RouteReuseStrategy {
        shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; }
    
        store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void { }
    
        shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; }
    
        retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null { return null; }
    
        shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
            return future.routeConfig === curr.routeConfig;
        }
    }
    As you can see, by default Angular does not use much of this functionality.  The only method that has any functionality is the shouldReuseRoute, everything else is null or false.  This article will discuss the ways these methods can be utilized together to enhance the functionality of the Angular router. 

    In order to use a custom implementation of the RouteReuseStrategy, you need to complete two steps:

      1. Create a class extending the RouteReuseStrategy – a sample minimal implemenation is below that uses the default Angular functionality as a starting point:
    export class CustomReuseStrategy extends RouteReuseStrategy {
        retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
            return null;
        }
    
        shouldAttach(route: ActivatedRouteSnapshot): boolean {
            return false;
        }
    
        shouldDetach(route: ActivatedRouteSnapshot): boolean {
            return false;
        }
    
        shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
            return future.routeConfig === curr.routeConfig;
        }
    
        store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {
        }
    }
    2. Create a provider to inject your custom class in your application’s main module:
    providers: [
        { provide: RouteReuseStrategy, useClass: CustomReuseStrategy}
    ]
    We will examine a sample situation and discover how these methods work and can enhance Angular functionality.

    Example Situation

    A common situationin web applications is a master-detail relationship.  There is some master page (e.g. search results) which the user can select individual details to view.  In this pattern, we are going to set a few constraints for how we want the application to perform:

     

      • The master page should have some interactivity state that should be maintained between detail views such as sorting, filtering, etc. – we will represent this by a random number displayed in the component where if we maintain the same random number we can demonstrate a preservation of the state of the component

     

      • The detail is viewable via a distinct URL containing an ID for the detail record

     

      • The detail view should load the details upon routing and be able to run some initialization for the detail 

     

      • Components need to run cleanup code when destroyed such as unsubscribing from observables – we will represent this by logging a message to the console. 

     

    We can implement two commonly used designs to meet the requirements.  As we will see, each can have some drawbacks and areas that we can gain additional control using the RouteReuseStrategy.  Both approaches will use the same detail page and a similar base class for the master page. 

     

    Shared Components

    This example will share as much as possible between the implementations to help distill the different approaches to only the differences. 

    Master

    The first shared functionality is a base abstract class to be used by the master page.

    export abstract class MasterComponent implements OnInit, OnDestroy {
        public randoms: number[];
        public abstract displayName: string;
    
        ngOnInit(): void {
            this.randoms = [];
            const numberOfLinks = this.getRandom(10);
            for (let i = 0; i < numberOfLinks; i++) {
                this.randoms.push(this.getRandom(100));
            }
        }
    
        getRandom(max: number): number {
            return Math.floor(Math.random() * max);
        }
    
        ngOnDestroy(): void {
            console.log(Destroy </span>${<span>this</span>.<span>displayName</span>}<span>);
        }
    }

    There are a few things happening in this component to take note of: 

    1. When the component initializes, it generates a new list of results – this represents user interaction with a list of items such as filtering or sorting
    2. The component logs a message with an identifier to be overridden by the consuming component

    Detail

     Both approaches will use the same detail component:

    @Component({
        selector: 'app-detail',
        template: ` 
          <div class="alert alert-primary" role="alert"> 
             <strong>Detail ID:</strong> {{routeParam}} 
          </div> 
     
          <div> 
             <strong>Random value:</strong> {{randomVal}} 
          </div> 
       `
    })
    export class DetailComponent implements OnInit, OnDestroy {
        public routeParam;
        public randomVal: number;
    
        constructor(private route: ActivatedRoute) { }
    
        ngOnInit(): void {
            this.route.params.subscribe(p => this.routeParam = p.detailId);
    
            this.randomVal = Math.floor(Math.random() * 100);
        }
    
        ngOnDestroy(): void {
            console.log(Destroy detail: </span>${<span>this</span>.<span>routeParam</span>}<span>);
        }
    }

    There are a few things happening in this component to take note of:

      1. When the component initializes, it gets the route parameter from the URL to display in the view – this represents any data loading for the detail from a back-end service
      2.  

      3. Generates a new random value to display in the view – this represents some view initialization for the detail page
      4.  

      5. The component logs a message with the route parameter when it is destroyed 

       

      Parent-Child Design

      The first design is a parent-child relationship where the contents of the master page stay on screen when viewing the detail.  This is best used when the detail is small and can reasonably fit on the same page. This method places a router-outlet in the master page to display the child content: 

    @Component({
        selector: 'app-parent',
        template: ` 
          <h1>Parent Component</h1> 
          <ul class="nav nav-tabs"> 
             <li class="nav-item" *ngFor="let random of randoms"> 
                <a class="nav-link" [routerLink]="['detail', random]" routerLinkActive="active">Go to {{random}}</a> 
             </li> 
          </ul> 
     
          <router-outlet></router-outlet>`
    })
    export class ParentComponent extends MasterComponent {
        displayName = 'ParentComponent';

    And adds the detail as a child route for the detail in the application route configuration:

    {
        path: 'parent', 
        component: ParentComponent,
        children: [
            {
                path: 'detail/:detailId',
                component: DetailComponent
            }
        ]
    }

    We can test and see how this setup meets our needs when navigating between detail pages:

     

    It is also important to note that the console for the application is completely empty, but when navigating elsewhere we see the destroy message. 

    When comparing these results to our requirements, we see the following results: 

     

    • PASS – Master page is maintained 

     

    • PASS – Detail view is a unique URL 

     

    • FAIL – Detail view initialization does not run – the random value is the same every time even when routing between different details

     

    • PARTIAL – Detail component is never cleaned up between detail views, but it is after navigating away 

    This approach initially results in one failure and one partial that we need to review.  Why does this fail to meet our requirement? 

    Look at the Angular DefaultRouteReuseStrategy class – specifically the shouldReuseRoute method.  The implementation returns true when the destination route has the same route configuration as the source route.  When going from one detail to the next this is always true – only the parameter changes and the same route configuration and components are used.  When the shouldReuseRoute method returns true, Angular will not destroy the component tree in turning firing the ngOnInit and ngOnDestroy hooks – instead the only thing that happens it the router emits new values for the route parameters and other Observables.  Therefore, we see the Detail ID update but not the random number.   

    We could easily solve the random number generation issue by moving the code into the subscribe callback on the params Observable.  This is often the best method in a detail type view to distinguish between code that creates the component and updates its contents when new data arrives or the route parameter changes.  Angular is designed around the idea of using Observables for communication and it shows here.  Most of the time, using the approach of binding to the param update instead of the overall life-cycle hooks will meet your application needs, but what happens when it doesn’t?  What if we really need the ngOnDestroy hook to fire when navigating away for that parameter and not just the component? 

    Returning to the RouteReuseStrategy – we can provide a custom implementation of the shouldReuseRoute method. We can set up a custom class implementation as discussed earlier copying the functionality of the default Angular implementation.  The only change we will make now is to not reuse any routes: 

    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        return false;
    }

    With only this change let’s test again and see what happens when we select a detail this time:

    The ngOnDestroy hook runs all right, but we’ve made this far worse.  The ngOnDestroy hook ran for the ParentComponent as well and we lost the state of the parent, we have new random links so a fresh search to the back-end has been called and the user loses all interaction.  We can now see why Angular has the default functionality we saw earlier.  When a routing event happens, it doesn’t just happen at the detail level.  Angular needs to review the entire component tree generated by the route.  When routing between siblings, the default functionality keeps the parent components intact and only rebuilds what is necessary – which not only gives a mostly expected behavior but has large performance benefits as well.  

    What we need is a way to direct Angular to only rebuild certain components but reuse others by default.  We want to add the default functionality back in to shouldReuseRoute and only deviate when we specifically request it.  We can accomplish this by using the data property on the route configuration which is designed exactly for this type of extensibility to a route.  Let’s add a flag to the detail route definition: 

    {
       path: 'detail/:detailId',
       component: DetailComponent,
       data: {
          alwaysRefresh: true
       }
    }

    And check for this in shouldReuseRoute: 

    shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
        if (future.routeConfig === curr.routeConfig) {
            return !future.data.alwaysRefresh;
        } else {
            return false;
        }
    }

    Now to test again:

     

    Excellent!  We now are only rebuilding the detail component and we leave the parent component untouched.  We have a design that meets all our requirements – just be aware of the consequences if the detail view is to have any children added to it. 

    Search-Detail

    The other design approach is to create two separate pages, a search results page and a detail view page.  This situation becomes far more desirable than the Master- Detail as the detail page gets larger and adds functionality that doesn’t easily fit on a single page.  It is also very reasonable for a single site to employ both approaches – for example JIRA allows users to switch between both display options when reviewing search results. 

    To implement this approach, we create sibling routes instead of a parent-child relationship.  These can be moved around to different parents depending on the desired URLs for the application, but we will put both under an empty parent to match the URL design of the Parent-Child approach: 

    @Component({
        selector: 'app-search',
        template: ` 
          <h1>Search Component</h1> 
          <ul class="nav nav-pills flex-column"> 
             <li class="nav-item" *ngFor="let random of randoms"> 
                <a class="nav-link" [routerLink]="['detail', random]" routerLinkActive="active">Go to {{random}}</a> 
             </li> 
          </ul> 
       `
    })
    export class SearchComponent extends MasterComponent {
        displayName = 'SearchComponent';
    }
    And the updated route configuration:
    {
       path: 'search',
       children: [
          {
             path: '',
             component: SearchComponent
          },
          {
             path: 'detail/:detailId',
             component: DetailComponent
          }
       ]
    }
    We can revert the custom RouteReuseStrategy and disable it to see how this approach works by default:

     

     

    Let’s review how this stacks up against our requirements: 

    • FAIL – The master page loses its context when we return to it 
    • PASS – Detail view is a unique URL 
    • PASS – Detail view initialization runs and gives a new random value 
    • PASS – Detail component is cleaned up between detail views 

    This approach gives an opposite problem as the Parent-Child design.  We initialize the detail view as expected, but we lose the context of the search results.  

    NOTE: The problem we had before with the initialization of the detail view still would exist if the detail view provided a direct link to another detail – this approach just doesn’t show it with this testing because we are using the master page to navigate between details.  

    As we are navigating to a new page, we need some way to store the results of the search page somewhere in memory so we can retrieve it when returning to the page.  There are three commonly seen approaches to this: 

    1. Using a service or other state management technique, but this approach often requires manually binding everything in the component into a service which gets tedious and error prone as the application grows. 
    2.  

    3. Use the Parent-Child approach and hide or cover the parent page when a detail is visible (e.g. detail is a modal window or some other overlay).  This again can work for simple implementations but has drawbacks for side effects and requires tightly coupling the components. If trying to use a full screen overlay this can also have adverse effects on usability if the user uses the back button to try to go back to the parent.
    4.  

    5. RouteReuseStrategy to the rescue! 

    To see how we can use RouteResuseStrategy we need to examine the process of routing and how the methods are used: 

    1. shouldDetach – This determines if the route the user is leaving should save the component state.  
    2.  

    3. store – This stores the detached route if the method above returns true.
    4.  

    5. shouldAttach – This determines if the route the user is navigating to should load the component state.
    6.  

    7. retrieve – This loads the detached route if the method above returns true.

    With these methods, we would expect the following for our custom implementation: 

    • shouldDetach returns true for the search results page and false for all other routes 
    •  

    • shouldAttach returns true when we have a saved search result 
    •  

    • we need a way to clear a saved search for when the user conducts a new search 

    Let’s start with a similar approach we took before by adding a flag to the route configuration.  This could also be done through identifying the URL or any other identification technique: 

    {
       path: 'search',
       children: [
          {
             path: '',
             component: SearchComponent,
             data: {
                saveComponent: true
             }
          },
          {
             path: 'detail/:detailId',
             component: DetailComponent
          }
       ]
    }

    This gives a straightforward approach to the shouldDetach method: 

    shouldDetach(route: ActivatedRouteSnapshot): boolean {
        return route.data.saveComponent;
    }

    And to store the component we need an internal map to use for storage, we can add this as a private property to the custom RouteReuseStrategy class: 

    private savedHandles = new Map<string, DetachedRouteHandle>(); 

    And now to store the component under a unique key (this is important to prevent conflict between multiple saved routes if this strategy is used for multiple routes): 

    store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle | null): void {
       const key = this.getRouteKey(route);
       this.savedHandles.set(key, handle);
    }
    
    // Routes are stored as an array of route configs, so we can find any with url property and join them to create the URL for the rotue
    private getRouteKey(route: ActivatedRouteSnapshot): string {
       return route.pathFromRoot.filter(u => u.url).map(u => u.url).join('/');
    }

    That completes the setup for saving the component when leaving, now to check if we should load a saved component when navigating to a route we can check if we have anything saved for the provided route and return the value as needed: 

    shouldAttach(route: ActivatedRouteSnapshot): boolean {
        return this.savedHandles.has(this.getRouteKey(route));
    }
    retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null {
       return this.savedHandles.get(this.getRouteKey(route));
    }
    

    Now we can test with this implementation of RouteReuseStrategy: 

    Success!  We are maintaining the search result component state across navigation and creating a new detail component for each detail we view. 

    There is one remaining item to address, what happens when we want to conduct a new search?  Even if the contents of the search result page are populated via an Observable, we may still want the ngOnInit hook to fire to reset the sorting, filters, pagination, etc.  We need a way to clear the saved component on demand.  Let’s create a method to do so in the custom RouteReuseStrategy class: 

    public clearSavedHandle(key: string): void {
        this.savedHandles.delete(key);
    }

    We need a way to access this method however.  Think back, what is the key to implementing a custom RouteReuseStrategy in the first place? We implemented a provider – we can use that! This would likely happen in a service and be executed whenever the user conducts a new search, but for simplicity lets add a button on the detail page: 

    <button class="btn btn-danger" (click)="clearStoredRoute()">Clear Search</button> 
    And bind it in the component: 

    constructor(private route: ActivatedRoute, private routeReuseStrategy: RouteReuseStrategy) { }
    
    clearStoredRoute(): void {
       (this.routeReuseStrategy as CustomReuseStrategy).clearSavedHandle('/router-reuse/search/');
    }

    Note we need to cast the injected object to our custom class – the injection token is for the abstract class so that’s all that Typescript gives us.  Also note that we need to provide the URL key that was generated in our class implementation as the saved handle key.  Keep this in mind when determining an implementation for triggering a save of a route.  This example mixed a URL route and route config data, but generally a single approach is preferred for simplicity and maintenance.  

    A word of caution: do not use the Component type as a key!  This seems to be a perfect approach as it provides a unique key, can be made independent of URL changes, etc. however it may work in a development environment and fail in production when minification is applied.   

    Let’s see this in action – first a test to make sure it still works as before then clearing the search: 

     

    There we have it – a new search result any time the Clear Search button is clicked.  There is one very subtle problem left.  We have a new search component – but the old one never got destroyed! This would result in memory leaks and other potential unintended consequences.  When Angular detaches a component, it pulls it out of its responsibility and hands it over to our RouteReuseStrategy implementation.  When we cleared the saved handle, we just removed the object from our tracking map, but that never triggers the lifecycle hooks we would expect.  Let’s add some logic to address this in our custom RouteReuseStrategy: 

    public clearSavedHandle(key: string): void {
       const handle = this.savedHandles.get(key);
       if (handle) {
          (handle as any).componentRef.destroy();
       }
    
       this.savedHandles.delete(key);
    }
    
    

    We have access to the component instance itself from the saved handle so all we need to do is call destroy to trigger the destruction life-cycle of the component. 

    RouteReuseStrategy – Maintaining Component State on Navigation
    Conclusion

    The most appropriate summary of the RouteReuseStrategy is this: with great power comes great responsibility.  It is an extremely powerful tool to customize Angular and greatly improve the user experience of your application – however there are various pitfalls to consider to safely implement its usage in a way that prevents some mysterious and difficult to identify bugs. There is one other downside – the functionality is not obvious to other developers as the majority of the functionality happens in the internals of Angular. Comments and documentation are crtitical for this approach to support fellow developers that are tasked with future maintenance. Even with the caveat, it remains a very power addition to the Angular toolbelt to quickly solve some common challenges.

    Next Topic – 11 of 11: Testing Complex Component Interaction

    11 – Testing Complex Component Interaction

    Testing Complex Component Interaction

    Overview

    Angular comes built in with a testing suite to help build and run automated testing, with some help from Karma (test runner) and Jasmine (test framework). This article assumes general knowledge of the Angular testing suite, if you aren’t familiar you can see the Angular Guide. This article aims to cover some complex testing scenarios that arise with component interaction using the techniques provided in the previous articles in this series and how to accurately test the situation.

    To follow along with the articles there a two repositories created: a starting point and final solution.

    The Situation
    Let’s say you have read and are following the 1- Smart vs. Dumb Components article… because you should!  When creating the smart components, you will be faced with some challenges during testing.  As a recap, the smart component functions like a controller, it’s job is to be aware of the application state and bind that information to the dumb (or other nested smart) components and to process the output from those components.  If we want to test the smart component in a unit test, how can we mock the dumb components to give ourselves enough control to easily trigger and interact with the inputs and outputs of those components?

    Let’s say we have a reporting dashboard with 3 components, a criteria component, a results component, and an input component.  The input component provides the trigger to run or update the report, but we need to get the criteria from a separate component in order to know what to run.  That builds a request to send to a service, and displays the resulting data in the results component.  We have some unique situation that prevents the input component from interacting with the criteria component, for example the input is a toolbar and the criteria is a filter section in another location.  We will need to get the criteria as it current is set at any point – this means we need to use ViewChild instead of an Output event:

    @Component({
        selector: 'app-report',
        template: <br /></span><span>        <app-report-criteria #criteria></app-report-criteria><br /></span><span>        <app-report-input (runReport)="refresh()"></app-report-input><br /></span><span>        <app-report-results [data]="reportResults"></app-report-results>
    })
    export class ReportComponent {
        public reportResults: ItemInterface[];
        @ViewChild('criteria') criteriaComponent: ReportCriteriaComponent;
    
        constructor(private searchService: SearchService) { }
    
        public refresh() {
            this.reportResults = null;
            if (this.criteriaComponent.validateCriteria()) {
                const criteria = this.criteriaComponent.getSearchCriteria();
                this.searchService.search(criteria).subscribe(data => this.reportResults = data);
            }
        }
    }

    The Solution

    To test this component, we will need to generate a testing component that we can use to render instead of the actual component.  The first step we can implement is leveraging TypeScript to provide some insurance that our mock implementation aligns with our actual implementation.  We can do this by using an interface that we implement for the component and the mock component.  Let’s implement an interface now.  We can even make it generic to the type of data we get from the service so we could re-use this for other criteria or forms:

    export interface ReportCriteriaFormInterface<T> {
        validateCriteria(): boolean;
        getSearchCriteria(): T;
    }
    export class ReportComponent {
        public reportResults: ItemInterface[];
        @ViewChild('criteria') criteriaComponent: ReportCriteriaFormInterface<SearchInterface>;
    
        //SNIP...
    }
    Now we know we are interacting with a consistent interface that we need to mock.  This is not a required element, but it certainly helps ensure our tests stay in sync with the implementation.

    Mock Component

    Let’s start by creating our test spec, if there is anything unfamiliar here then review the testing documentation from Angular.  We set up a standard test with a service spy providing some dummy data.

    describe('ReportComponent', () => {
       let component: ReportComponent;
       let fixture: ComponentFixture<ReportComponent>;
       let searchService: jasmine.SpyObj<SearchService>;
    
       const testData: ItemInterface[] = [
          { name: 'Apples', description: 'Juicy, red, and delicious' },
          { name: 'Socks', description: 'So your feet don\'t get cold' },
          { name: 'Tires', description: 'Because we sell everything' }];
    
       beforeEach(() => {
          searchService = jasmine.createSpyObj(['search']);
          searchService.search.and.returnValue(of(testData));
    
          TestBed.configureTestingModule({
             declarations: [ReportComponent],
             providers: [
                { provide: SearchService, useValue: searchService }
             ],
             schemas: [NO_ERRORS_SCHEMA]
          }).compileComponents();
          fixture = TestBed.createComponent(ReportComponent);
          component = fixture.componentInstance;
    
          fixture.detectChanges();
       });
    
       it('should create the component', () => {
          expect(component).toBeTruthy();
       });
    });
    Sometimes the easiest option is to use the actual component.  For our user input that is just a button that emits an event, we can set that up for this test case.  If you expect or implement additional complication later this may not be the best approach, but sometimes there is no need to reinvent the wheel just to have a pure unit test.  Let’s bring the component into our test module and create a test that clicks the submit button:
    describe('ReportComponent', () => {
       // SNIP
       TestBed.configureTestingModule({
          declarations: [ReportComponent, ReportInputComponent],
          providers: [
             { provide: SearchService, useValue: searchService }
          ],
          
          // SNIP
    
          it('should run a search', () => {
          fixture.debugElement.query(By.css('button')).triggerEventHandler('click', {});
          expect(searchService.search).toHaveBeenCalled();
       });
    });
    The test fails, our search method is never called!  What gives?  The component method is checking the validation of the ReportCritiera component before running the search.  Since we aren’t declaring the component, the NO_ERRORS_SCHEMA lets us run the test, but the criteriaComponent property is null, so the validateCriteria() is undefined.  We need a way to easily test what happens when the criteria is and is not valid, but this is not a case we want to use the existing component as there can be too much logic that bleeds into our test.  Let’s create a mock component we can use instead, thankfully we have an Interface to implement so we can match the component design!
    @Component({
        selector: 'app-report-criteria',
        template: ''
    })
    export class MockReportCriteriaComponent implements ReportCriteriaFormInterface<SearchInterface> {
        public isFormValid = true;
        public searchData: SearchInterface;
    
        validateCriteria(): boolean {
            return this.isFormValid;
        }
        getSearchCriteria(): SearchInterface {
            return this.searchData;
        }
    }
    A few items to note about this.  First, we can create this component anywhere, but there are two places that I suggest.  The first option is to create this inline with the test, just add it before the describe method – this works best when the test component is only used for that specific test.  The other option is to create a test folder, generally under the src folder and along side the app folder.  This folder is a good location for any testing utilities such as mock data, components, helpers, etc.

    Secondly, notice the selector of the component.  This must match the selector for the actual component.  This is how Angular finds the component to inject in the template, so the selector (and Inputs and Outputs) must match.  We just need to declare the component in our test to use it:

    describe('ReportComponent', () => {
       // SNIP
       TestBed.configureTestingModule({
          declarations: [ReportComponent, ReportInputComponent, MockReportCriteriaComponent],
          providers: [
             { provide: SearchService, useValue: searchService }
          ],
          // SNIP
    });
    Finally, you can see we implement the interface, but have added some public properties to provide the return values.  We just need to perform a cast operation when accessing the component reference through our component to have access to those properties.  We can now easily interact with the mock component to update our test:
    it('should run a search', () => {
       const mock = component.criteriaComponent as MockReportCriteriaComponent;
       mock.isFormValid = true;
       const testSearch = {searchTerm: 'foo'};
       mock.searchData = testSearch;
    
       fixture.debugElement.query(By.css('button')).triggerEventHandler('click', {});
       expect(searchService.search).toHaveBeenCalledWith(testSearch);
    });
    We can also easily create a test for invalid criteria:
    it('should not run a search for invalid criteria', () => {
       const mock = component.criteriaComponent as MockReportCriteriaComponent;
       mock.isFormValid = false;
    
       fixture.debugElement.query(By.css('button')).triggerEventHandler('click', {});
       expect(searchService.search).not.toHaveBeenCalled();
    }); 

    Testing Complex Component Interaction
    Conclusion

    Writing tests is one of the best ways to evaluate your application architecture to ensure you are adequately using abstraction and isolation of application funcationality.  There are many techniques that can greatly enhance your abilities when building an application, but if you can’t test or isolate the functionality you are going to pay the price in the long term with maintenance.  The modular nature of Angular can greatly support that initiative by allowing for on the fly replacement of components and other dependencies with simple and easy to control alternatives.

    For A Team That Brings More To The Project Than Just Heads-Down Programming: Contact Us Today!

    GET TO KNOW US

    Consultant

    Dave Cloutier – Author

    Business and technology acumen have dovetailed in Dave Cloutier’s career, making him an ideal Intertech consultant. After an early start as an aerospace engineer, Dave became a business analyst at Prosar (now ProPharma Group). While maintaining most of his business analyst responsibilities, he also became lead developer and led the implementations of multiple enterprise systems. Dave joined Intertech in 2019, where he devises creative solutions to complex problems. He is a natural teacher and leader who can work individually or as part of a team.

     

    “Risk versus reward is the critical factor in most decisions,” says Dave. “There rarely are times when difficult decisions have an obvious choice. Finding the choice that maximizes the potential reward for an acceptable level of risk only can be done when a solid relationship exists between the client and consultant.”

     

    Why Did You Choose Technology Sales?

    I believe IT solutions are at their best when the lanes of communication between developers and end users are open. Developers who know the ins and outs of the business can design creative solutions using emerging technology that end users may never have imagined. An open, creative and iterative approach yields better software and pushes both sides to learn and grow.

    Sideline

    I like to pretend that I’m good at hockey and play in an adult winter league, but my favorite hobby is woodworking. I’m slowly working to replace all the furniture in my house with something I made. After working in a virtual world during the day, it’s refreshing to build something physical!

    Custom Application Development For All Your Line-of-Business Needs!

    Intertech Logo

    Understanding your industry is one thing. Understanding the technology you are using is another. When you read studies that tell you that 75% of projects are doomed from the beginning, it has to make you pause before signing your name to the outcome.

    Consider letting our proven professionals take a look at your project. They’ve seen what can go wrong and know how to avoid costly errors.

    At Intertech, we ask the right questions and tell you the correct answers. From design to rollout, Intertech takes the worry out of custom software development. Add the unique benefit of our field-driven education division, and you get a blend of exceptional knowledge that plugs in, does what you need, and leaves your business and employees more engaged and more potent as a team. 

    We Bring You…

    Team-Complete™ Development

    Intertech’s Team-Complete™ development means we make sure all the right people are seated at the table to assure success the first time. At Intertech, you always get the best of the best! Proven consultants dive deep into your project, analyze your objectives, and lead your project to success with the expertise and the soft-skills you expect from a leader.

    Soft-Skills For A Winning Experience

    Sometimes the most critical person in the room is the one with a calm voice and the right words. Bringing a development team together or presenting a clear concept for stakeholders can make all the difference between success or failure. Intertech consultants are at the top of their field. They navigate challenging decisions, guide with a confident voice, and know when to get out of the way.

    Tell us how we can help!

    Intertech takes the worry out of custom software development.

    Discover All That Intertech Can Do For You!

    Let’s Build Something Great!

    Tell us what you need and we’ll get back with you ASAP!