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. Check it out here.

 

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

Let’s be honest, it’s pretty common that when your pipe isn’t running how you think it should in Angular, you can sometimes just tack on the “pure : false” tag like so

@Pipe({
  name: 'myPipe', 
  pure : false
})

And you just hope for the best. But this actually has severe consequences for your application, and in some cases can grind your entire application to a halt. It’s also extremely easy to end up with infinite loops or memory issues as an impure pipe can easily end up running far more often than you realize. But let’s rewind a bit, what’s this “pure” business about anyway?

Pure Pipes

A “pure” pipe (Which I have to say, I don’t like the naming.. It’s not that intuitive…), is an Angular Pipe that only runs when the underlying variable value changes. So for example if I had the following

{{ myVariable | myPipe }}

Then myPipe would only run when myVariable changes value. This typically means on load, and then anytime that variable is touched. But there is a small caveat. Let’s say for example I have a variable that looks like so :

myVariable : any = { propertyA : "foo"};

And then I am piping my variable as normal

{{ myVariable | myPipe }}

What happens when I do the following?

myVariable.propertyA = "bar";

Does the pipe run again? The answer is actually no. The easiest way to understand this is that it’s only looking if the top level value of the variable changes. It does not look at child properties at all. The only way for this pipe to be run again is to change the entire instance of myVariable like :

myVariable = { propertyA : "bar"}

But that’s somewhat impractical. You can’t be rebuilding the entire object every time just so a pipe can run. And you may even be trying to pipe an object you have no control over how it’s being set. So that’s where impure pipes come in.

Impure Pipes

Introducing Impure pipes, you can make *any* Pipe impure just by setting the pure flag to false in your declaration :

@Pipe({
  name: 'myPipe', 
  pure : false
})

Now instead of running every time the value changes, it runs often, *much* more often. Specifically it runs every digest cycle which is essentially Angular’s internal loop. Generally speaking, you may be running the pipe every time you move your mouse or use your keyboard. There’s a couple of issues this may cause :

  • You are now running code irrespective of changes to the underlying data, meaning there is a lot of time wasted doing unneeded work.
  • Depending on how heavy your pipe is, you could slow down your app trying to process work that doesn’t need to be done.

The second point is important. If your Pipe is doing something with a large piece of data, for example sorting a large array, it’s impractical to be doing this every digest cycle.

You’ll even notice this little tidbit from the Angular documentation around the lack or filter/orderBy pipes in the framework :

Angular doesn’t provide pipes for filtering or sorting lists. Developers familiar with AngularJS know these as filter and orderBy. There are no equivalents in Angular.

This isn’t an oversight. Angular doesn’t offer such pipes because they perform poorly and prevent aggressive minification. Both filter and orderBy require parameters that reference object properties. Earlier in this page, you learned that such pipes must be impure and that Angular calls impure pipes in almost every change-detection cycle.

Filtering and especially sorting are expensive operations. The user experience can degrade severely for even moderate-sized lists when Angular calls these pipe methods many times per second.

So as a framework, Angular has gone to pains to point out that even pure pipes should be lightweight and try and do as little heavy lifting as possible. Let alone if you are doing impure pipes.

A good trick to get into is to just add a simple console.log inside your pipe to see how often it’s being run, the results may blow your mind and make you think twice about switching to impure.

Good Examples Of Impure Pipes

For good examples of impure pipes, we can look at which pipes in the framework are marked as impure. These are :

  • JsonPipe
  • SlicePipe
  • KeyValuePipe

Key to all 3 of these pipes are that they are working on objects, not primitive values (So require Impure pipes to detect “deep” changes), and all of them do a very simple process to output the data. For example the JsonPipe simply does a stringify on an object (Essentially a one liner). It doesn’t mean that these are particular performant and should be used everywhere, but they are a good example of “when you have to”.

As an example of the absolute worst thing you could do would be to make an HTTP Call from an Impure pipe. This will surely result in thousands of HTTP calls to an API and your page grinding to a halt.

Using Input Parameters Instead Of Impure Pipes

There may be times where you need to pipe a particular object, but within that object you are only using a couple of properties to derive the pipe output. You can get around having to use an impure pipe by instead using input parameters on your pipe. Using our object from earlier :

myVariable : any = { propertyA : "foo"};

We can then create a pipe that looks like so :

@Pipe({
  name: 'myPipe'
})
export class myPipe implements PipeTransform {
  transform(myVariable : any, inputParam : any): string {
    return inputParam;
  }
}

In my HTML I can then call the pipe like so :

{{ myVariable | myPipe:myVariable.propertyA }}

The pipe will run when myVariable changes *and* when propertyA changes. You don’t even have to use the parameter (Or the initial input variable) inside the pipe, but you can still use them to “trigger” the pipe. This can also be handy when you need the pipe to trigger based on another objects parameter. This can feel hacky at times and if your pipe is lightweight enough, it can be simpler to just to go impure, but it’s an option if you don’t want things firing multiple times per second.

There’s going to be a couple of assumptions for this guide on adding App Insights to an Angular app. The biggest of all is that you are familiar with the Application Insights product itself. Maybe you’ve used in an another app before, maybe in a C# backend application or maybe a React/Vanilla Javascript app. But the biggest thing is that you know what it does and how to create an instance in the Azure Portal.

So with that out of the way. Why use Application Insights at all in an Angular App? The biggest win of all is that it can be used to track every application error thrown by your application, both handled and unhandled. And the second is that it can be used to track pageviews of users as they move through your SPA, which can then be used to track navigation paths, where users drop off in your sign up process, how your pipelines perform etc.

With all that said and done. Let’s jump right into it.

Installing Application Insights Libraries

The first thing we need to is install the following NPM package

npm install @microsoft/applicationinsights-web --save

Now this next piece of code is going to look big but it should be easy to understand. We want to create an “ApplicationInsightsService” that can handle logging exceptions, setting the logged in user, and tracking page views. The service contents will look like so :

import { Injectable } from '@angular/core';
import { ApplicationInsights, IExceptionTelemetry, DistributedTracingModes } from '@microsoft/applicationinsights-web';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class ApplicationInsightsService {
  private appInsights : ApplicationInsights;

  constructor(private router: Router) {

    this.appInsights = new ApplicationInsights({
      config: {
        instrumentationKey: "YourKeyHere"
      }
    });

    this.appInsights.loadAppInsights();
    this.loadCustomTelemetryProperties();
    this.createRouterSubscription();
  }

  setUserId(userId: string) {
    this.appInsights.setAuthenticatedUserContext(userId);
  }

  clearUserId() {
    this.appInsights.clearAuthenticatedUserContext();
  }

  logPageView(name?: string, uri?: string) {
    this.appInsights.trackPageView({ name, uri});
  }

  logException(error : Error){
    let exception : IExceptionTelemetry = {
      exception : error
    };
    this.appInsights.trackException(exception);
  }

  private loadCustomTelemetryProperties()
  {
    this.appInsights.addTelemetryInitializer(envelope => 
      {
        var item = envelope.baseData;
        item.properties = item.properties || {};
        item.properties["ApplicationPlatform"] = "WEB";
        item.properties["ApplicationName"] = "My.Application.Name";
      }
    );
  }

  private createRouterSubscription()
  {
    this.router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((event: NavigationEnd) => {
      this.logPageView(null, event.urlAfterRedirects);
    });
  }
}

So a couple of notes :

  • LoadCustomTelemetryProperties can be used to set “custom” properties inside ApplicationInsights. This is handy to name your app, or pass through specific information that isn’t normally captured by AppInsights.
  • CreateRouterSubscription allows us to listen for navigation events and then log these as pageviews. By default AppInsights only logs full page refreshes so you will need this if you are using the internal Angular router.
  • LogException can be used to log exceptions, but you need to inject this service manually for it to be of any use (We will look at that shortly).
  • The @Injectable attribute has been told that the provider is for the root, this means there will only ever be one instance of this service for your entire app (Singleton).

Error Handling

So in theory the Application Insights javascript packages should catch all unhandled errors. But in reality Angular actually catches any internal errors (for example a bug in your code), and has it’s own way of handling them. This kicks in well before AppInsights as a chance to see the error, and so you won’t actually see your exceptions being logged to AppInsights at all!

Let’s fix that. We want to create an ErrorHandler implementation that does nothing but log the exception to AppInsights, and print out to the console (If we want to). The code looks like :

import { ErrorHandler, Injector, Injectable } from '@angular/core';
import { ApplicationInsightsService } from './application-insights.service';

@Injectable()
export class ApplicationInsightsErrorHandler implements ErrorHandler{

  constructor(private injector : Injector)
  {
  }

  handleError(error: any): void {
    this.injector.get<ApplicationInsightsService>(ApplicationInsightsService).logException(error);
    console.log(error);
  }
}

Now I know the use of Injector here is a bit flaky, but there is a bit of reasoning behind it. I found that when dealing with exceptions, if they were issues with the error handler or the AppInsightsService itself, I ended up in infinite loop territory when trying to inject things in normally. The use of Injector isn’t ideal, but it works and typically broke out of loops before hitting max callstack exceptions.

In our NGModule, we then want to create a provider for our error handler :

@NgModule({ 
  declarations: [
	...
  ],
  imports: [
	...
  ],
  providers: [
    ...
    { provide : ErrorHandler, useClass : ApplicationInsightsErrorHandler},
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

We use the token of ErrorHandler so Angular knows that we want to use this particular class for handling all errors. And that’s it!

Using Distributed Tracing With CORS

If you are attempting to setup distributed tracing with CORS (That is your API is something like api.mydomain.com and your front end is mydomain.com), then there is some more mucking about to do before you get there. It’s a headache, I can assure you.

The first is that CORS is not turned on within the App Insights Angular library by default. To do so, in our ApplicationInsightsService we want to pass in an extra flag when creating our ApplicationInsights object :

this.appInsights = new ApplicationInsights({
  config: {
	instrumentationKey: "YourKeyHere", 
	enableCorsCorrelation : true
  }
});

Next you need to set up your backend app for CORS. Now this will be different depending on what language you are using. My suggestion would be to google “YourLanguage Setup CORS” and follow the steps from there, then right at the end you need to look how to set up “ExposedHeaders”. We need to expose the header “request-context” otherwise the token AppInsights uses to link up requests is not passed back and forth.

As an example, in C# .NET Core, it would look like :

app.UseCors(x =>
    x.AllowAnyOrigin()
        .AllowAnyHeader()
        .AllowAnyMethod()
        .WithExposedHeaders("request-context")
);

Only then will your application pass the distributed tracing tokens back and forth.

Obviously you will also need to wire up Application Insights for your backend application which will completely depend on which backend language you are using. But almost all “support” distributed tracing out of the box, just not using CORS.

If you’ve ever sifted through job boards or even stackoverflow when it comes to Angular, you will see people use the terms “AngularJS” and “Angular” interchangeably. Or atleast that’s what it can sometimes appear to be. But AngularJS and Angular actually refer to two very different versions of Angular. While learning one basically gets you half way to learning the other, they are not necessarily interchangeable. So what’s the difference?

AngularJS Is Angular 1

Before we jump into the actual differences between AngularJS and Angular. The first thing you need to know is that the term “AngularJS” is typically used to refer to the very “first” version of Angular, Angular 1. When Angular 2 rolled out, it had tonnes of “breaking” changes from version 1. Infact it was a completely different architecture! Where Angular 1 used things like Controllers and used Scope/Rootscope, Angular 2 did away with these and made everything in your app a “component”.

Naturally some were adverse to such a hard shift and given that many applications were already written in version 1, people didn’t want to have to go through and update their entire application architecture so they stuck with it. Even as further versions of Angular rolled out (Angular 4, 5, 6 etc), Angular 1, now called AngularJS, received it’s own updates with things like performance boosts and security upgrades. For some, this meant AngularJS was still a very viable alternative to creating a Single Page App without having to re-learn a new framework.

Feature Comparison Between AngularJS And Angular

As mentioned above, Angular 2 introduced a completely new architecture of “everything” being components. Because of this you could almost say it’s a different JS framework, but I’ll try and list out a couple of important differences between the two versions.

  • Angular uses Typescript (as default but you can use Javascript also) while AngularJS uses plain Javascript.
  • Angular makes everything a “component” and you use these as blocks to create your app. While AngularJS is primarily MVC (Model-View-Controller) based.
  • Angular makes uses of it’s own CLI to create components, run tests, serve the app etc while AngularJS does not have a CLI at all.
  • Angular has it’s own inbuilt packaging system using Webpack while AngularJS requires you to roll your own (Often Gulp, but you can also use Grunt or Webpack)
  • AngularJS requires different attributes to say whether you want two way or one way binding (e.g. ngModel vs ng-bind) whereas Angular just uses [] or ()
  • Angular has a component based CSS encapsulation concept, AngularJS does not
  • Angular supports server side rendering, AngularJS does not

This is by no means an exhaustive list. Realistically, I could list out many “annoying” gotchas with AngularJS that were fixed in Angular 2+. For example data binding in Directives is a right pain to learn in AngularJS and is by no means intuitive, you need to learn crazy text symbols to work out how multi directional binding works :

{
   scope: {
     text: "@myText",
     twoWayBind: "=myTwoWayBind",
     oneWayBind: "&myOneWayBind"
   }
}

Whereas in Angular this is just so much more intuitive.

Should You Start A New Project On AngularJS Or Angular?

Angular. 100% Angular.

On July 1st 2018, AngularJS entered into lifetime support mode. This means it’s not actively being worked on (feature wise), and new releases will only contain security fixes or critical bugs caused by a new browser version. This is expected to last until June 2021 at which point support will end. So at best the AngularJS you have right now will continue to be the same in the future, and at worst from mid 2021 onwards your framework will no longer be “supported”.

Angular just fixes so many issues with AngularJS with a very small learning curve. If you know AngularJS already, then getting started on Angular won’t be a hassle at all. If you are starting fresh and thinking of building your first SPA, there is no reason to pick a framework with notable gotchas that will run out of support in a years time.

Yes, we should always be doing unit tests, E2E tests, integration tests, and whatever other sort of tests are the flavor of the month. But you might also find yourself working on a proof of concept that tests are just going to be overkill on.

Even so, each time you run an ng generate command, you end up with an annoying spec file that isn’t too hard to delete, but is just hella annoying to have to do each time. Luckily Angular provides a way to turn off spec files via the CLI. Let’s take a look.

When Creating A New Project

When creating a new project, there is a way to skip the entire rest of this tutorial by one simple flag.

ng new --skipTests

When creating your new project, simply pass the –skip-tests flag and “theoretically” it should skip *ALL* tests right?

Well wrong (As of Angular 8). You will probably see the following fly by :

CREATE SkipTestsFromStart/e2e/protractor.conf.js (808 bytes)
CREATE SkipTestsFromStart/e2e/tsconfig.json (214 bytes)
CREATE SkipTestsFromStart/e2e/src/app.e2e-spec.ts (651 bytes)
CREATE SkipTestsFromStart/e2e/src/app.po.ts (262 bytes)

So as it turns out there is an open bug on the Angular Github Repo for this exact issue : https://github.com/angular/angular-cli/issues/9160. Personally I think it makes sense that when you say “Hey, I’m not doing tests”, that you actually mean it, but Angular gonna Angular.

So if it still creates the e2e folders, what does it actually do when you pass –skipTests? Well it adds the following into your angular.json file :

{
  ...
  
  "projects": {
    "SkipTestsFromStart": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss",
          "skipTests": true
        },
        "@schematics/angular:class": {
          "skipTests": true
        },
        "@schematics/angular:directive": {
          "skipTests": true
        },
        "@schematics/angular:guard": {
          "skipTests": true
        },
        "@schematics/angular:module": {
          "skipTests": true
        },
        "@schematics/angular:pipe": {
          "skipTests": true
        },
        "@schematics/angular:service": {
          "skipTests": true
        }
      }
	  
	 ...
}

What it’s essentially doing is saying “Hey, when I create these things, don’t create tests”. So for example if we run the following command :

ng generate component MyNewFeature

It won’t generate the spec file along with it. Awesome!

When Working On An Existing Project

You may have already created your project so passing the –skipTests flag to the ng new command isn’t going to cut it. So you have two ways you can work around this (Or really one if I’m being honest).

The first way is less than ideal because 9 times out of 10 you forget to pass the flag. That is, when you run ng generate , you can pass skipTests in there :

ng generate component MyNewFeature --skipTests

Note that in older versions of Angular this was a spec flag that you passed true or false in. This has now been deprecated but if you are on an old version of Angular it will look like so :

ng generate component MyNewFeature --spec=false

It’s quickly going to become a headache to always pass this into your generate commands. So a better way is to take the above schematics JSON that we talked about in the “When Create A New Project” section, and put that into your angular.json.

For example, if I don’t want new components generating a spec file, we can add the following to our angular.json file :

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "MyProject": {
      "projectType": "application",
      "schematics": {
        "@schematics/angular:component": {
          "style": "scss",
          "skipTests": true
        }
.....
}

I’ll also note that you can pick and choose where you do this. For example you could disable tests for components only, but still generate tests for your services, pipes and guards.

The best way I’ve found to get the JSON just right is to create a brand new project in another folder using

ng new --skipTests

And then copy and paste over the JSON you need. This will also give you a good idea of what how fine grain you can go when turning off tests (Or not turning them off as it might be).

In almost all of my Angular projects, one of the first things I add is a simple AppConfig service that allows me to swap out configurations on the fly for different environments. In most cases, this is so that I can set a different base API endpoint for my different environments, and have them swapped in at release time. Let’s jump into it!

Why Not Just Use Angular Environments?

So Angular actually has an inbuilt concept of “environments” (more info here) that is pretty similar to a typical appconfig setup. But the main issue is that this environment is also tied to individual builds. In modern day scenarios we want to build *once* and release multiple times. If our app settings are swapped out/configured at build time, this doesn’t afford us the ability to only build once and deploy multiple times. Instead we are building a different distribution for each environment.

Instead, I would highly recommend keeping Angular Environments for settings that you want to have at build time (e.g. Turn off Debug), rather than setting up individual settings between Dev,  Test,  Production etc.

App Config Is Not A Secret Store

The next thing I want to touch on is that no matter what we do in Angular, it’s still a front end web technology. That means that, even if we obfuscate things a bit, any user can still view the source code. In this tutorial, we are using a publicly available JSON file as our application configuration file, so even more so, it’s not a secret store. Do not put anything in there that you don’t want shared to the public.

Really, in most cases we are just going to be putting in there a API base endpoint and maybe a couple of other small config params that change markup. But nothing like like DB Connection Strings, authentication tokens etc.

Create Our Config Files

The first thing to do is to create a couple of configuration files in a safe directory. By safe I mean that Angular will just take the directory as a whole and output it when building. We don’t want Angular to do anything with our config files, just copy them when we build.

For that reason I typically choose the assets  folder which is created when you create a new Angular project from the CLI.

So in a folder at /assets/config  I create two files. The first is just called app-settings.json with the following :

{
    "apiBaseUrl": "https://localhost:5001"
}

And then I create another called app-settings.production.json with the following :

{
    "apiBaseUrl": "https://myapi.com"
}

So that’s our config files ready to go!

Creating The AppConfig Service

Next create a new service using the Angular CLI called AppConfig. Then replace all the code with the following :

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

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

  private appConfig: any;
  private http : HttpClient;
  
  constructor(http: HttpClient) {
	this.http = http;
  }

  loadAppConfig() {
    return this.http.get('/assets/config/app-settings.json')
      .toPromise()
      .then(config => {
        this.appConfig = config;
      });
  }

  get apiBaseUrl() : string {
    return this.appConfig.apiBaseUrl;
  }
}

Let’s walk through this a little, even though it’s pretty simple.

We have a method called loadAppConfig that essentially calls our config files we created earlier, then loads them into a local appConfig object that is basically a dynamic type.

We then have a property called apiBaseUrl that will return the apiBaseUrl that we just retrieved from our json file.

But there’s a problem. Before we can retrieve the apiBaseUrl, we first need to call loadAppConfig. And we only really want to do this a single time to load the file into memory, after that any further calls to load the json file are a complete waste. We could write some code in here with a boolean to check if we have loaded the config already, and if we haven’t to load it, and then continue. But that’s naff.

Luckily Angular already has a feature to help us!

Using APP_INITIALIZER To Load Configuration

In a previous post we talked about how to use APP_INITIALIZER in Angular to do a “one time” activity when the Angular app bootstraps for the first time. If you haven’t come across this feature before, I highly recommend going to read it because the following might not make much sense otherwise : Using The APP_INITIALIZER Token To Bootstrap Your Application. 

All we need to do is head to our main app.module.ts, and add a line to our providers array that looks like so :

providers: [
	{ 
	  provide : APP_INITIALIZER, 
		multi : true, 
		 deps : [AppConfigService], 
		 useFactory : (appConfigService : AppConfigService) =>  () => appConfigService.loadAppConfig()
	}
]

What this does is say, when our app is started, can you please call the following method. Our loadAppConfig method actually returns a promise anyway, but our application will wait until this promise completes before continuing on.

It may seem backward to wait until our configuration file loads to continue loading our application. Won’t the startup time be noticeable? Maybe. But we also can’t be sure what will be calling the config service and, more importantly, when. So it’s better for us to just load everything up front and be ready when things hit us.

Swapping Configurations At Release

Now comes the easy, but… different… part. By different I mean this next step will totally depend on how you release your application. The nuts and bolts of it is that when you release to say, production, you will need to rename the file app-settings.production.json to app-settings.json. That way when your service loads your configuration file, it’s the right one for that specific environment.

For me, because I’m doing releases from Azure Devops, I wrote a quick piece of powershell to simply rename the file. But you can use any sort of script, or maybe even an inbuilt step in your release pipeline can do it. Either way, renaming the file is the last step and you are ready to go with your brand new app config service in Angular!

Angular has a great CSS feature called “View Encapsulation”. It means that each component can have it’s own CSS that is encapsulated and applied to only that particular component/view. This does away with having to have great big long CSS declarations to try and narrow down the element you want to style. For example you probably have seen gnarly things like :

.main-page #header-wrapper #header-div #header-left-panel h1 span{

}

With Angular’s View Encapsulation that is no more (Well… Atleast most of the time).

But you may come across some situations where the view encapsulation gets in your way. Where you know the element you want to style, but the additions in the shadow dom are making things a headache. Luckily Angular adds in a couple of CSS Pseudo Elements that help you “break out” when you need to. These include :host, :host-context and ::ng-deep. Today we’ll do a dive on :host.

:host In A Nutshell

Imagine I create a component called “my-component” that’s pretty darn simple :

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

@Component({
  selector: 'app-my-component',
  template : `<p>This is my component</p>`,
  styleUrls: ['./my-component.component.scss']
})
export class MyComponentComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

}

Now if I want to style the component itself? How do I do that? How can I style the <app-my-component>  tag? A beginners take might be to try some CSS/SASS like so :

app-my-component
{
    display:block;
    background-color:blue;
}

After all, I’m using the name of my tag inside itself so hopefully it should be recognized. Wrong. Angular view encapsulation means I can only style things “inside” the component, but not the component itself. Unless I use the :host pseudo element of course :

:host
{
    display:block;
    background-color:blue;
}

Remember this goes *inside* the components style file, and not in the root etc. Using :host I am able to self style the component! It’s almost like using the “this” keyword in Angular CSS syntax.

What Goes On Under The Hood?

When your view is compiled down, your components are given unique attributes to encapsulate styles from one other. So in my example, app-my-component actually gets output looking like :

<app-my-component _ngcontent-lsw-c0="" _nghost-lsw-c1="">
	<p _ngcontent-lsw-c1="">This is my component</p>
</app-my-component>

The way it works (in a simple way) is that each component is given an _nghost-unique-id . Each element that lives inside that component is then given an _ngcontent-unique-id  . Where the unique-id on the ngcontent label matches that of the parent nghost. Pretty smart stuff!

So that goes a ways to explain why when we try our beginners attempt of just using the component tag :

app-my-component
{
    display:block;
    background-color:blue;
}

It doesn’t work because the generated CSS actually looks like :

app-my-component[_ngcontent-lsw-c1] {
  display: block;
  background-color: blue;
}

So notice that it’s saying our tag should have an _ngcontent tag with a specific id but we are actually looking for the same tag with an _nghost.

When we check how it generates and outputs the :host tag, it looks like :

[_nghost-lsw-c1] 
{ 
	display: block; 
	background-color: blue; 
}

Makes sense! It outputs the exact tag it knows our component will have, allowing us to style the component itself, not just it’s children.