Detecting clicks on a particular component/element that you have complete control over is fairly trivial in Angular, but what about if you want to know when a user clicks somewhere on the page on something that is *not* inside a particular component. It may sound like a weird edgecase but it’s actually really common when building things like custom popup modals or even just custom dropdown/select controls. With these you often want to detect if a user clicks away from the component so that you can hide the modal/popup or slide up the dropdown control.

I couldn’t find anything really talking about this particular issue but as it turns out, it’s pretty easy to get up and running!

Let’s assume I have a component called “DropDownComponent” that I want to detect if there are clicks *outside* of this control. Basically if there is a click anywhere else on the webpage. The first thing we have to do, is inject a reference to ourselves in the constructor.

constructor(private elementRef: ElementRef) {
}

When ElementRef is injected this way, Angular injects in the HTML native element that this component is drawn into, which is perfect for us because now we know in plain javascript/html, what our element is referenced as.

The next piece of the puzzle is actually very trivial. Inside our component we add a HostListener that listens for any document:click.

@HostListener('document:click', ['$event.target'])
public onPageClick(targetElement) {
  const clickedInside = this.elementRef.nativeElement.contains(targetElement);
  if (!clickedInside) {
	//Do something. 
  }
}

The code itself is pretty self explanatory. We detect any document clicks (Which is a click anywhere on the page), and in doing so, we detect exactly what element was clicked. Next we determine if the element that was clicked lives inside our component by using the injected ElementRef we put in the constructor, if it doesn’t, then bingo, we know that the user has clicked outside of the component and we can run whatever custom code we wish to (e.g. Close the modal, slide up the dropdown list etc).

This probably looks a little heavy handed (And it is really… ), but a good thing to note is that HostListeners are destroyed when the component they belong to is destroyed. So unless you attach this to every single component, you’ll generally only have 1 or 2 of these document click listeners running at any one time.

I was working with a piece of code recently that made liberal use of the “Tap” operator on an observable. I’ve seen it used pretty often, but everytime I try and find documentation to show a junior developer how it works, I always find it a really overcomplicated mess. Tap, infact, is a really simple operator on the surface that you really shouldn’t have a hard time understanding.

Let’s jump straight into some code. The most common use-case for using tap is because you want to use the result of an observable elsewhere, but still pass the exact same result back to any subscriber.

For instance let’s say that I want to call an API to fetch the current user, and I want to do nothing more than log that user to the console, and then return that same user out. A very naive way to achieve this would be :

this.http.get<User>('api/user').pipe(map((user : User) => {
	console.log(`Current User Is : ${user.name}`)
	return user;
}));

Theoretically not a heck of a lot wrong with this, I mean it works, but it’s not nice. You are calling the map function purely so that you can log the user, but then you aren’t actually mapping anything, and instead returning the same user. The result of this function is still Observable<User> so the caller doesn’t know what’s going on behind the scenes, but it’s messy.

One of the worst ways I’ve seen someone try and achieve this looked like so :

return Observable.create((observer: Observer<User>) => this.http.get<User>('api/user').subscribe((user : User) => {
	console.log(`Current User Is : ${user.name}`)
	observer.next(user)
	observer.complete()
}));

I mean talk about RxJS word salad. It’s a mess. And we don’t need to do this if we just use Tap!

Taking the above example and using Tap.

this.http.get<User>('api/user').pipe(tap(user => { 
	console.log(`Current User Is : ${user.name}`) 
}));

Notice how we used tap to write the console log, but we didn’t have to return the user object. It’s because we are saying that Tap will do something with the user object, but the original user should be returned to whoever is subscribing.

Another way to remember what tap does is that you are “tapping” into the result. Like a wiretap almost! You are listening in but (theoretically), you aren’t interfering with the existing conversation.

There is one caveat when using Tap though, and that is that the object inside the tap is still a reference to the original, it’s not a clone. So for example :

//This will return a user object with the firstName of test. 
this.http.get<User>('api/user').pipe(tap(user => { 
	user.firstName = 'Test';
}));

I personally prefer to use Tap only when the method inside the tap is safe and has no side effects that would alter the original result. If I am going to be altering the original result, I prefer to use the Map operator because that signals that we are “mapping” what the original result was to something new (Even if it’s only changing a single property).

A common issue when adding a required attribute to a textbox/textarea in an Angular application is that someone can just press space bar once, and the “required” validation is completed. A space counts as character!

The simple way to get around this is to use a regex pattern attribute to validate that there is more than just a space. Something like :

<input type="text" pattern="^(?!\s*$).+" />

But this quickly gets annoying to copy and paste everywhere. A better solution if you need to validate multiple fields the same way is to create a nice directive. Here’s one I prepared earlier :

import { Directive } from '@angular/core';
import { NG_VALIDATORS, Validator, ValidationErrors, AbstractControl } from '@angular/forms';

@Directive({
  selector: '[noWhitespace]', 
  providers: [{ provide: NG_VALIDATORS, useExisting: NoWhitespaceDirective, multi: true }]
})
export class NoWhitespaceDirective implements Validator {

  constructor() { }

  validate(control: AbstractControl): ValidationErrors {
    if(!control.value || control.value.trim() == '')
    {
      return {'required' : true };
    }

    return null;
  }

}

Simply place this on any text input/area control like so :

<input type="text" noWhitespace />

And you will now validate that the control has a value *and* that the value is not just whitespace. Easy!

I came across an interesting challenge recently that involved being able to pass a “template” between components. In my particular case, I had a “table” component that simply laid out tabular data, nothing too crazy. In most cases I simply wanted the text value of a property to be displayed, but in some rare cases, I needed a custom template to be shown. While it may seem simple, simply pass through a string variable with HTML inside and be done with it, when it comes to data binding, it actually becomes a bit more complex than that.

I quickly came across TemplateRef in the Angular documentation which sounded like what I needed, but as is the case with many Angular internals, the documentation was somewhat lacking. So let’s explore TemplateRef and see what it can actually do.

The Basics

The basics to actually get a “TemplateRef” variable in the first place looks like so. Let’s say I create a component called “ParentComponent”. I’m going to create the HTML (thus far) looking like so :

<ng-template #myTemplate>
    <h1>This is my Template</h1>
</ng-template>

All this is doing is creating a “template” object called #myTemplate. This actually doesn’t render anything to the page, it simply tells Angular that at some point, you will use this template somewhere. I think it’s probably pretty similar to Handlebars templating if you’ve ever used that before.

Now the code behind our component will be very simple.

export class ParentComponent implements OnInit {

  @ViewChild('myTemplate', {static : true}) myTemplate : TemplateRef;

  myModel = {
  };

  constructor() { }

  ngOnInit() {
    this.myModel =  {
      template : this.myTemplate
    }
  }

}

So all we are doing here is using ViewChild to get a reference to the actual template and storing it in a TemplateRef variable. I’m also creating a “model” object. Although you don’t have to do this, from my MVC days I prefer creating a “ViewModel” to pass between components. In our case we want to create a second component to accept this template.

So I’m going to create a component called ChildComponent. The code behind the component looks like so :

export class ChildComponent implements OnInit {
  
  @Input() model : any;

  constructor() { }

  ngOnInit() {
  }

}

It will accept an input of “any” which in our case will be our model we created in our ParentComponent. Really I should create a proper strongly typed class here but for now, the type of any will suffice.

For the HTML of our child component, we then need to do the following :

This is my child component. <br />

<ng-container *ngTemplateOutlet="model.template"></ng-container>

What we are doing here is outputting an ng-container that is given a template (The template we passed through) to render.

If we go back to our ParentComponent and add the child tag to it so the HTML ends up looking like :

<ng-template #myTemplate>
    <h1>This is my Template</h1>
</ng-template>

<app-child [model]="myModel"></app-child>

Run everything and wham! Our template is passed through to our child component that renders it perfectly!

Why Not Use NG-Content?

So another way to achieve this is using the <ng-content> tag which we will definitely talk about in another post. But if a developer is asking you why not just use that? Well… After using it for a while I’ve found that the ng-content tag is great for single projections, but if you are wanting to pass multiple templates into a component ng-content is a little bit more rough around the edges on how that works. The other thing I found was that the data binding was no where near as intuitive in ng-content as it is using ngTemplateOutlet.

Databinding?! You can do that?! You sure can. Let’s take a look at hot it works.

Databinding NgTemplateOutlet

A very common scenario for templates is that you will want to databind values inside the actual template. The issue with this is, what is it binding to? In our example above, if we added data bindings to our template would it be binding to the ParentComponent since that’s where the template is defined, or would it bind to the ChildComponent because that’s where the template is actually output?

The answer is neither. It doesn’t bind at all unless you specify where it should bind and to what.

Let’s modify our template to bind a subheading. The way to make this work looks like :

<ng-template #myTemplate let-data="data">
    <h1>This is my Template</h1>
    <h4>{{data.subheading}}</h4>
</ng-template>

So you’ll notice we do a “let” command above. What that says is, I’m going to be passed a value called “data” (That’s the data actually inside the quotes), when I’m given that, bind it to a variable called “data” that is scoped to this template.

Then below, I will expect on this data object to be a subheading property.

Go back to our ParentComponent and change how we bind the model to also have a subheading property :

ngOnInit() {
  this.myModel =  {
    template : this.myTemplate, 
    subheading : 'this is my subheading'
  }
}

Because we are still passing through our model to the child component, the binding and codebehind there stays the same. But inside the actual HTML of the ChildComponent we have to tell it the context we want to give it. We do that like so :

This is my child component. <br />
<ng-container *ngTemplateOutlet="model.template; context: { data : model}"></ng-container>

So notice on the *ngTemplateOutlet, we pass in a context. Now personally, I like to create another “sub” object with a key value like this. This means that you can pass in multiple values on the same object etc, but it’s up to you.

Now when our template is run, it knows about this object called “data”, and can use that to bind values. Super easy!

I have a pretty easy rule when it comes to using NG-Deep on my projects, “if you think you need it, I would think a little harder”. 9 times out of 10 when I see people using the ng-deep modifier, it’s because they want a “quick fix” without really thinking through the consequences. And in the majority of those cases, the use of ng-deep comes back to bite. I want to talk a little more about NG-Deep “bleeding”, and how the lazy loading of styles in Angular often hides the issue until things are already in production.

What Is NG-Deep?

NG-Deep is essentially a CSS pseudo element that allows you to “break” CSS encapsulation. For example let’s say that I have a very simple component like so :

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-first-parent',
  template: `<app-child></app-child>`,
  styles : ['h1 { color:red; }']
})
export class FirstParentComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

Notice a couple of things, that the template is simply a component called “child”, and on this particular page, I want all H1 tags to be red. Well you may think that if I create the child component like so :

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `<h1>This is a child component</h1>`,
  styles: []
})
export class ChildComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

We might at first suspect that the H1 tag is going to be red. But if we view it in a browser, it doesn’t work!

When we check the page source for our styling, we can see it looks like so :

h1[_ngcontent-iqb-c1] { color:red; }

The _ngcontent is our view encapsulation taking hold. Because we have put our H1 styling into our FirstParent component, it’s limited that styling to *only* that component. Because our H1 is actually in a child component, we are a bit shafted.

But hold on, we’ve heard about this amazing thing called ng-deep that basically removes encapsulation for components in Angular! Let’s try it!

If we change the styling of our FirstParent component from :

styles : ['h1 { color:red; }']

To :

styles : ['::ng-deep h1 { color:red; }']

Does everything work?

It does! And when we check the source code we can see that the styling has had the view encapsulation removed and it’s just a plain h1 style now!

<style>h1 { color:red; }</style>

So everything works right?

Adding Another Component

Let’s add another component that’s almost identical to the first. We’ll call it “SecondParent”.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-second-parent',
  template: `<app-child></app-child>`
})
export class SecondParentComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

This one is identical to the first, except that we don’t have any styling for our H1s. We instead just want to use the default styling.

We will also add some routing so that if we go to /firstparent, we are taking to the FirstComponent, and /secondparent goes to the second. The routing looks like so :

const routes: Routes = [
  { path : 'firstparent', component : FirstParentComponent}, 
  { path : 'secondparent', component: SecondParentComponent}
];

For this to work, we want a button on the FirstParent that goes to the Second, and vice versa. To make things easier for ourselves, we want to change the FirstParentComponent to have the following template :

template: `This is the first parent. <br /><app-child></app-child> <a [routerLink]="['/secondparent']">Go To Second Parent</a>`

And the SecondParentComponent should have :

template: `This is the second parent. <br /><app-child></app-child> <a [routerLink]="['/firstparent']">Go To First Parent</a>`

While theoretically the template changes aren’t needed, for this next little demo it will make things easier to see.

Let’s try a couple of straight navigation options.

If I go directly to /firstparent, I see :

This is correct. We get the red H1 tag.

If I go directly to /secondparent (By direct I mean typing it in my browser and not clicking the link), I see :

Also correct, we have the black H1 and not the red. Perfect!

Let’s try something else, if we go directly to /firstparent, then click the link to go to the SecondParent, what happens?

So.. When we go direct to /secondparent, everything works fine, but if we go to /firstparent, then navigate via Angular to the /secondparent, it all goes wrong. Why?

Well it’s actually a simple explanation.

CSS in Angular is LazyLoaded, that means that any styles for a particular component are only actually loaded when that component is itself loaded. For us that means that we only get our special ng-deep rule when FirstComponent is actually loaded, but if we go direct to the SecondComponent from our URL bar, then it doesn’t need to load that CSS and so doesn’t.

The reason I want to point this out is because in the majority of cases where I see ng-deep go wrong, it’s been incredibly hard to track down bugs where sometimes you have to go through a series of pages to recreate the bug. In our example, imagine if a tester/QA logged a bug that said when they went to /secondparent, the text was red. Well if we just tried to recreate it by going directly to that page, we wouldn’t see the issue!

At the crux of it though, we see that using ng-deep the way we have done causes big issues because we are essentially writing an H1 rule to the global stylesheet. It’s the exact issue that view encapsulation tries to fix, but then gives us the tools to wreck it anyway.

Working Without NG-Deep

Let’s look at some ways to work without NG-Deep, or more so ways in which we can limit our exposure to bugs like above.

Using :host

First up is my favourite, and one that Angular actually recommends, and that’s prepending any ng-deep rule with the :host modifier. We have a great article on how to use :host here! But in simple terms, if we change our rule inside FirstComponent to look like so :

styles : [':host ::ng-deep h1 { color:red; }']

What we are essentially saying is that we still want to go “deep”, but only when we are inside this particular component. The rule itself when written to the page looks like :

[_nghost-qxj-c1] h1 { color:red; }

Where the _nghost is the FirstComponent, and it’s saying any H1s inside this component can be red, but any H1s inside any other component will not be affected.

Being More Specific

If for some reason you don’t want to use :host (Or can’t), then another option is to simply be more specific in your rules that are going to be global. For example if we changed our template and styling inside FirstParent to look like so :

template: `This is the first parent. <br /><div class="first-parent-wrapper"><app-child></app-child></div> <a [routerLink]="['/secondparent']">Go To Second Parent</a>`,
styles : ['::ng-deep .first-parent-wrapper h1 { color:red; }']

So notice how we have now wrapped our child control in a very specific class, that we can then use for our styling. Even though this rule will be global, it’s unlikely (But not impossible), that someone somewhere else uses the same “first-parent-wrapper” class. But again, you are essentially breaking view encapsulation and banking that no one else uses this class name anywhere else.

Passing Variables

Of course the final option, which should be pretty obvious,¬† is that you can ofcourse pass styles or even switches to a child component. So you can create an input parameter for your child component called “headerText”, and then pass in the color you want it to be. This does have it’s limits though in that generally you are looking for a direct parent to child relationship, and you don’t want to be passing around styling several layers deep. But it’s an option!

Work Without It

This isn’t really a solution but one that always pays to keep in mind. Use of NG-Deep should be a last resort. It should be used when you really can’t find any other way to achieve what you are doing. You’ve asked on stackoverflow and on the Angular Github tracker, and there’s just no other possible way to do things without NG-Deep. Even then, you should use one of the above methods to limit your exposure.

Over the past couple of months I’ve been doing battle with an Angular Universal project. Angular Universal is Angular’s answer to Server Side Rendering or SSR for short. Why use SSR? In most cases it’s for SEO purposes but in some cases it also gives “perceived” performance.

For SEO, when opening a link to an SSR website, Angular renders the complete (Or semi-complete) page on the server, and returns the HTML that can be read by search engines (and other robots).

When I say “perceived” performance, what I mean is that because it’s atleast semi-rendered,¬† a user doesn’t see a flash of a blank screen like you normally get with regular Angular apps. I personally don’t think it really returns the complete page any faster than a regular Angular App, but the first paint is more “complete” than that of a regular Angular app.

It sounds good on the surface, but just try and have a quick search for how many people are actually using Angular Universal in production – there’s not many. Almost every tutorial you find on the subject is the Angular Universal equivalent of a “Hello World”. I won’t say I’m an expert on Angular Universal, but I wanted to write this article to maybe show you a couple of things that every tutorial leaves out of the conversation.

Library Support Is Rough

The first thing you probably learn when using Universal is that when the page is rendered on the server, it doesn’t have access to a couple of really important (common) javascript paradigms. Among them, you can’t access the window object (Since this refers to the browser window of which there isn’t one when doing server side rendering), you can’t access things like localStorage or any sort of memory that might live inside a browser window like Session Storage. Cookies are also a bit of an issue for obvious reasons.

Angular recommends you wrap things that need to access these objects inside a method called isPlatformBrowser so that you can check if you are in that moment doing server side rendering or if you are doing it in a browser. (More info here https://github.com/angular/universal/blob/master/docs/gotchas.md).

But, that’s with your code. What about something like an authentication library that uses localStorage? Like the MSAL library from Microsoft that allows your javascript application to integrate with Azure AD. They have a great Angular package that makes authentication a cinch. But they obviously haven’t gone and wrapped everything in browser checks. Why would they muddle their code with that when very very few people are using Angular Universal anyway?

And I ran into this same problem many times over. Even just libraries that try and access the window object (which has to be pretty common in javascript), they are going to completely bomb out when running inside Angular Universal. Of course, you can always fork the code or try and add in a bunch of browser checks yourself, but the point is is that all those libraries that were plug and play on your last project suddenly become a headache to get integrated.

Development Is Extremely Slow And Confusing

Let’s face it, building Angular Universal bundles are slow. When you have a plain Angular app and you run “ng serve”, it’s snappy. The watchers are fast and changing a couple of lines typically only takes a couple of seconds to recompile. I’ve found Angular Universal to be the exact opposite. Often with recompiles taking almost the exact same time as the initial compile. Those jokes back in the day of “can’t work, code recompiling” when you were working on mainframes are back!

I also found debugging of Angular Universal apps incredibly complicated and often confusing. You see it’s only the *initial* request that is server side rendered. As you click around the site, you are then inside a regular Angular app and therefore everything is client side. But common debugging tools like console.log() become very confusing to follow because if it’s an initial request, that log will be written on the server, not in the browser, all subsequent logs will be written to the browser. Same goes for any debugging tool you might use. The initial request would be like debugging a typical Express application, but all subsequent requests can be debugged just fine from the browser. Trying to bring a new developer up to speed is pretty damn difficult.

Documentation Is Terrible

Finally. The documentation is terrible. Angular Universal has one, yes one, page of documentation here : https://angular.io/guide/universal. That’s it. I even had to log a bug that the sample application they provide doesn’t actually compile at all. And they closed it was they were “working on it”. So not sure how hard it is to just provide a working example of an Angular Universal app, but evidently it’s still not been updated.

Beyond the official documentation, you typically rely on other examples and blogs floating around on the web that really only scratch the surface of what Angular Universal does. If you run into any roadblocks at all, you are pretty much on your own because as far as I’ve seen, no one actually uses Angular Universal in any large commercial capacity (Happy to be proven wrong though!).

Should You Use Angular Universal?

I’m a big believer in using the right tech for the right purpose. As it stands right now, I believe that if you need server side rendering, then don’t use a client side javascript framework to do it. While it’s not too hard to turn any app into Angular Universal. On any project of reasonable size, you’ll start hitting roadblocks thick and fast and soon realize that Angular Universal is a fun POC, but not a commercial offering.

This article is part of a series on creating multi step form wizards in Angular.

Part 1 – Basic Setup
Part 2 – Building Our Forms
Part 3 – Tying It All Together


We are on the home stretch with our multi-step form, infact we are pretty much there! But I wanted to give a few more tips on tying everything together, including an awesome debugging trick.

The Final HTTP Post

Having a form is useless unless it actually sends data, and luckily for us, we already have a service prepared to do just that – our FormDataService! At the moment it looks like :

export class FormDataService{

  personalDetails : PersonalDetails;
  addressDetails : AddressDetails;

  constructor() {
    this.personalDetails = new PersonalDetails();
    this.addressDetails = new AddressDetails();
   }
}

Our best bet is to add a simple “postData” method that collates everything together and talks to some backend API (Not features). For example :

export class FormDataService{

  personalDetails : PersonalDetails;
  addressDetails : AddressDetails;

  constructor() {
    this.personalDetails = new PersonalDetails();
    this.addressDetails = new AddressDetails();
   }

   postData(){
     let newCombinedObject = {
       personalDetails : this.personalDetails, 
       fullAddress : this.addressDetails.fullAddress
     }

     //Use somthing like http.post etc to send the data to the backend server. 
   }
}

I know that this is a bit of a simplistic view, but it’s hard to get into the nitty gritty without also building out an actual API. The point I want to make here though is that we have all the models from all the different steps of the form, we can take all of that data and mould it into our API model. In my case, I have taken the full personalDetails object, but from the address I’ve taken out the individual property. It’s up to you to transform the data how you need it, but the idea is that it’s all there to play with!

Heading back to our Address Details component, if we add in a click event handler to our backend :

export class AddressDetailsComponent implements OnInit {

  addressDetails : AddressDetails;

  constructor(private formDataService : FormDataService) { 
    this.addressDetails = formDataService.addressDetails;
  }

  ngOnInit() {
  }

  submit(){
    this.formDataService.postData();
  }

}

And then bind our HTML to that click event handler :

<table>
    <tr>
        <td>Full Address</td>
        <td><input type="text" [(ngModel)]="addressDetails.fullAddress" #fullAddress /></td>
    </tr>
    <tr>
        <td><input type="button" value="Back" routerLink="" /></td>
        <td><input type="button" value="Complete" (click)="submit()" /></td>
    </tr>
</table>

And we have a full complete submit routine!

Debugging Helper

The biggest thing I struggle with when building out extremely large forms with multiple steps is testing each individual input. Namely, that when I get to the end of the form to submit… I’ve almost forgotten what it was I typed at the start!

There’s actually a nice way to debug this (Atleast in Dev). The first thing we want to do is go to a parent component of our entire form, in our example project’s case, that’s simply the app-component. The first thing we do is inject the formDataService into the backend.

export class AppComponent {
  constructor(public formDataService : FormDataService) {
  }
}

Then we need to edit the HTML of the AppComponent to output the models of the service as JSON. That looks like so :

<h1>My Multistep Form</h1> 
<router-outlet></router-outlet>
Personal Details : {{this.formDataService.personalDetails | json}} <br />
Address Details : {{this.formDataService.addressDetails | json}}

Now as we fill out the form, on all steps we have a live update of how our model actually looks on the backend.

Not only is it handy when we get to the end of the form to be able to see what we “should” be submitting just before we submit it, but also if we have any complex controls/custom controls in our form, we can see exactly what’s going on in the backend as we fill them out.

Is This The Best Method?

Finally I just want to touch on if this is the “best” way of achieving a multi step wizard in Angular. You could probably swap out “best” for “most efficient”, “proper”, “up to date”, however you want to say it. As I said early on, this is the way I’ve been building these sorts of forms since the very early days of Angular. It’s served me well and even with things like Reactive Forms and RxJS becoming increasingly popular, I find this to be the most straight forward method. There’s no hidden “magic” or library doing things on the backend, it’s just simple code that works.

This article is part of a series on creating multi step form wizards in Angular.

Part 1 – Basic Setup
Part 2 – Building Our Forms
Part 3 – Tying It All Together


In the last part of this series on building a multi step form wizard, we got a simple project up and running, but it wasn’t really doing a heck of a lot. Let’s change that by building out the HTML forms to capture some basic information.

Personal Details Form Build

The first thing we want to do is to generate a new component called “PersonalDetails”. We can do that in the Angular CLI :

ng generate component PersonalDetails

The first thing we need to do is wire up the component to pull in the service, and load the personal details model out. Without too much faffing about, it will look like :

export class PersonalDetailsComponent implements OnInit {

  personalDetails : PersonalDetails;

  constructor(private formDataService : FormDataService) { 
    this.personalDetails = formDataService.personalDetails;
  }

  ngOnInit() {
  }

}

Pretty simple really. Inject the service in, pull out the personal details model, and set it locally. Remember that because the FormDataService is a singleton, for our entire app (per page load), there will only ever be one instance.

Next, we can replace personal-details.component.html with the following amazingly styled HTML.

<table>
    <tr>
        <td>First Name</td>
        <td><input type="text" [(ngModel)]="personalDetails.firstName" #firstName /></td>
    </tr>
    <tr>
        <td>Last Name</td>
        <td><input type="text" [(ngModel)]="personalDetails.lastName" #lastName /></td>
    </tr>
    <tr>
        <td>&nbsp;</td>
        <td><input type="button" value="Next" routerLink="addressdetails" /></td>
    </tr>
</table>

Not yes, we are using tables. And yes this is not going to look great at all but it’s just a demo!

Everything here should be rather straight forward. We have two text boxes, and they bind to the personal details object on the component. Then we have a next button that routes to our (future) address details component. This link obviously won’t work right now, and will actually break everything if you try and view it! Grrr!

What we need to do is first create the AddressDetails component by going

ng generate component AddressDetails

Then we need to open up our app-routing.module.ts file, at the top will be a const of routes that will (probably) be empty right now. Change it to the following :

const routes: Routes = [
  { path : '',   component : PersonalDetailsComponent }, 
  { path : 'addressdetails',   component : AddressDetailsComponent }, 
];

This then wires up our two components, the first will be on the homepage, and the next will be at /addressdetails.

Run a quick ng serve, and we should end up with something like :

It’s not pretty, but it works! Click Next will take us to our AddressDetails component which is actually empty. So let’s fix that!

Address Details Form Build

We’ve already generated our AddressDetails component so that we could route to it, so let’s just fill it out.

Our component definition should look like so :

export class AddressDetailsComponent implements OnInit {

  addressDetails : AddressDetails;

  constructor(private formDataService : FormDataService) { 
    this.addressDetails = formDataService.addressDetails;
  }

  ngOnInit() {
  }

}

And the actual HTML of the component should look like :

<table>
    <tr>
        <td>Full Address</td>
        <td><input type="text" [(ngModel)]="addressDetails.fullAddress" #fullAddress /></td>
    </tr>
    <tr>
        <td><input type="button" value="Back" routerLink="" /></td>
        <td><input type="button" value="Complete" /></td>
    </tr>
</table>

Now we could go ahead and deep dive this code but I think it’s pretty self explanatory. In our component we load out the FormDataService which is actually the exact same instance we used in the PersonalDetails component (Infact we could access the PersonalDetails model if required here), and then we display a simple form bound to the AddressDetails model.

Now the most important think to notice is that if we run our solution and test it. We can type in our personal details, press next, enter in our address details, but then press *Back*. Our Personal Details are re-loaded out of our shared service and pre-populated into the form! We haven’t had to do some crazy loading/unloading of models into our form, simple data binding does the magic for us.

In the next part of this series, we will look at how we then post our data to an API, and some tips and tricks working with larger multi step forms.

 

This article is part of a series on creating multi step form wizards in Angular.

Part 1 – Basic Setup
Part 2 – Building Our Forms
Part 3 – Tying It All Together


I recently came across a question on social media asking what the best way to create a “multi stage” form wizard in Angular would be. Now multi stage might be one word for it, but I’ve also seen it called multi step, multi page, multi form, hell even just “form wizard”. But they all roughly mean the same thing – a big long form that should be done in one sitting, but is broken up (often into bite size sections) across multiple “pages”.

The solutions on social media mostly involved complex third party libraries, like piping results around using rxJS, or creative use of reactive forms in Angular etc. I might be showing my age here… But I’ve built multi step forms in the exact same way since Angular 1.6. Using a shared service to hold the form “state”, and simply sharing that service between different forms/components. I’m going to outline that solution here in a very simple way so that (hopefully), you can follow on and realize that while Angular can be powerful, it can often handle complex scenarios with very non-complex code.

Project Setup

The first thing we need to do is create a brand new project for the walkthrough. Using Angular CLI we can run our standard angular new project command :

ng new multistageform

Make sure to select “Yes” when asked if I wanted to add Angular Routing as we need this to route between different steps of the form.

Inside our app.component.html we want to replace the default content in here with :

<h1>My Multistep Form</h1>
<router-outlet></router-outlet>

This will be the starting point for our form. In a real world scenario we would probably go with some sort of nested routing strategy, but for our first cut, let’s make things simple! Fire up our angular serve command in the CLI :

ng serve

And we should be able to browse to localhost:4200 and be greeted with our project all nicely set up!

Shared Service Setup

The secret to making this multi step form work is a shared service that can hold “state” as we click next throughout the form. Go ahead and run the following CLI command¬† to generate a new service called “FormData”. I personally like throwing all my services into a services folder – it just makes things a bit easier to find.

ng generate service services/FormData

This should create a new folder called services in your app directory, and inside it should be form-data.service.ts. Also note that it’s decorated with the following attribute :

@Injectable({
  providedIn: 'root'
})

This just happens by default but it’s actually incredibly important to what we are doing. The providedIn : ‘root’ property tells Angular that the service should be created at the root level, and re-used for every component/service that requests it. In simple terms, our service will be a singleton. It will be created once, and that instance will be reused everywhere. This is super important for us because as we step through the form, we want to “share” data between steps and right at the end be able to grab all the data at once.

Let’s create a model to hold some data.

ng generate class models/PersonalDetails

This will generate a class to hold the “personal details” step of the form – just a first/last name for now. Replace the contents of your newly created class with the following :

export class PersonalDetails {
    firstName : string;
    lastName : string;
}

Go ahead and do the same and create an AddressDetails model

ng generate class models/AddressDetails

And fill it with the following class definition

export class AddressDetails {
    fullAddress : string;
}

Let’s head back to our FormDataService as we need to add references to our two new models.

There’s a few different ways we could go about this, we could do it with methods, properties, or just plain public variables. For now let’s just go with public variables. We will also want to “reset” our variables in the constructor which essentially means that on page load, we have an “empty” form.

So with all that in mind, our FormDataService should end up looking like :

@Injectable({
  providedIn: 'root'
})
export class FormDataService{

  personalDetails : PersonalDetails;
  addressDetails : AddressDetails;

  constructor() {
    this.personalDetails = new PersonalDetails();
    this.addressDetails = new AddressDetails();
   }
}

That’s all we will be doing with the service for now as we jump into actually building out our forms!

Following along so far? I’ve broken up the tutorial into bite sized chunks so it’s a little less daunting. Check out the next part of this series where we build out our multi step form with some very simple HTML and Angular components.

Angular 9 was released on Februrary 7th, 2020. Generally speaking, this isn’t a flashy release with lots of goodies, but instead a release that gives a huge (needed) update to plenty of behind the scene components.

Angular Ivy

Angular Ivy is the name given to Angular’s new compilation and rendering pipeline. Essentially when you build and package your Angular app, the HTML, JS and CSS you have written is all compiled and packaged up to be delivered to a users browser. While the way you write code doesn’t change, the way Angular builds thing has changed dramatically without you having to do anything. This results in :

  • Faster build times (Which is massive if you do any sort of git pre-commit hook using ng build!)
  • Smaller build package sizes (Less to deliver to the client results in your page loading faster)
  • Better understanding of how modules fit together unlocks better tree shaking, ability to lazy load components etc.
  • Improved CSS and style binding

And a tonne more!

Probably the most exciting thing to me are the first two. Faster build times is huge to me as I like to do a full build before checking any work in just to make sure everything is playing nice, but the slow down in commiting even a one line change is pretty big right now. Secondly, the smaller build packages are pretty amazing. There is this official image floating around that demonstrates the difference :

40% size decrease!? Sign me up!

What Else?

I get that Ivy maybe isn’t the most exciting thing in the world if you were looking to get your hands on something new and shiny. Angular 9 does have a bunch of bug fixes and deprecations, but nothing new that will completely blow you away. In terms of methods being deprecated, you can see the full list here : https://angular.io/guide/updating-to-version-9. Most notably are things like Renderer becoming Renderer2, and the <ngForm> tag becoming <ng-form>. Nothing too spectacular.

Upgrading

To update your existing application to Angular 9, simply run :

ng update @angular/cli @angular/core