Check out our Angular Book Series.

Do You Need Injectable Metadata? - Dependency Injection and Angular - Part 3

I was chatting with a colleague recently, and he had some confusion about how dependency injection works with Angular. There are a bunch of ways to set up Dependency Injection with Angular, but as always the documentation seems lacking. I'm writing this series of posts to discuss the ways and to explain what works and what won't work.

Check out the first post where we set up a project and created a default Angular Service, and part 2 where we remove the providedIn configuration object.

Do you need the Injectable Metadata?

It is a little known fact about Angular services that you do not need the injectable metadata at all to make things work. First, generate a new service:


ng generate service services/service3

Open it up:


import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class Service3Service {
constructor() { }
}

You've seen this in our previous samples. Now remove the injectable metadata completely and add a shared value into the service:


import { Injectable } from '@angular/core';
export class Service3Service {
myValue = 'default 3';
constructor() { }
}

This will still work as an Angular service, even without the appropriate metadata. The trick is that you need to add it to the app.module.ts file. Find the providers array as part of the NgModule metadata and add it:


providers: [
Service2Service,
Service3Service
],

Be sure to import the service:


import {Service3Service} from './services/service3.service';

Now, we can mirror our previous samples using service3. Switch over to view1.component.ts and inject Service3Service into the component:


constructor(public service1: Service1Service,
public service2: Service2Service,
public service3: Service3Service) { }

You'll have to import the Service3Service here:


import {Service3Service} from './services/service3.service';

In view1.component.html, add a bindable input to the service3 value:


<h1>View 1: Service 3</h1>
<input [(ngModel)]="service3.myValue">

Go over to view2.component.ts to inject service3:


constructor(public service1: Service1Service,
public service2: Service2Service,
public service3: Service3Service) { }

Add the service3 import:


import {Service3Service} from './services/service3.service';

And output the value:


<h1>View 2: Service 3</h1>
{{service3.myValue}}

Now rerun the app:

You should see everything working as expected. Type in the service 3 input of view 1 and the service 3 output in view 2 should output.

What's Next

You can play with the code here.

In the next article of this series, I'm going to show you how to set up providers for a specific component, instead of for the full application.

providedIn - Dependency Injection and Angular - Part 2

I was chatting with a colleague recently, and he had some confusion about how dependency injection works with Angular. There are a bunch of ways to set up Dependency Injection with Angular, but as always the documentation seems lacking. I'm writing this series of posts to discuss the ways and to explain what works and what won't work.

Check out the first post where we set up a project and created a default Angular Service.

This post will expand on the previous sample, and examine the providedIn configuration object to the Injectable metadata a bit more deeply.

Remove the providedIn as part of injectable metadata

Let's generate another service:


ng generate service services/service2

You'll see something like this:

Open up the file:


import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class Service2Service {
constructor() { }
}

We're going to add a property to this service to be shared:


myValue = 'default 2';

This is just like the last one. We're also going to change the Injectable metadata to remove the configuration object. Before the class definition, you should see:


@Injectable()

Now try to inject the provider into view1.component.ts . If you're building off the previous sample, you'll see this:


constructor(public service1: Service1Service, public service2: Service2Service) { }

Be sure to import Service2Service into the component:


import {Service2Service} from '../services/service2.service';

Rerun the app. It doesn't load. Look at the debugger console:

You see a lot of injector errors. Even though we created Service2Service with injectable metadata, Angular does not know how to find it. That is because we never told Angular how to find it. One way to do that is to set the providedIn object as we did in the previous sample. But we removed that metadata and such the error.

The alternative is to tell the Angular module to make this class available as an injectable service. We do this using the providers array on the NgModule annotation. Open up app.module.ts and add a providers array:


providers: [
Service2Service
],

Be sure to import the class here too:


import {Service2Service} from './services/service2.service';

Now re-run the app and you should get no errors. Unfortunately, we aren't do anything with service 2 yet. Let's mirror the sample we used for service 1. First, in view1.component.html, add an input that binds to service2:


<h1>View 1: Service 2</h1>
<input [(ngModel)]="service2.myValue">

Next, inject service2 into the constructor of view2.component.ts:


constructor(public service1: Service1Service, public service2: Service2Service) { }

Import Service2Service:


import {Service2Service} from '../services/service2.service';

Then update view2.component.html:


<h1>View 2: Service 2</h1>
{{service2.myValue}}

Now rerun the app:

As you type in the service 2 input of view 1; you should see the service 2 output from view 2 update. It works perfectly.

What's Next

You can play with the code here.

In the next article of this series, I'm going to remove the injectable metadata completely and see how that works.

Creating an Angular Service - Dependency Injection and Angular - Part 1

I was chatting with a colleague recently, and he had some confusion about how dependency injection works with Angular. There are a bunch of ways to set up Dependency Injection with Angular, but as always the documentation seems lacking. I'm writing this series of posts to discuss the ways and to explain what works and what won't work.

This post will explain what Dependency Injection is, create a basic Angular application, and generate a default service.

What is Dependency Injection?

First I want to explain what Dependency Inection is. Dependency Injection is a fancy way to say you're automatically passing one class access to another. The dependency is called a service, while the receiving object is called the client. The process of creating the service is done outside the client, so the client does not need any knowledge of how to create its dependencies, it can just use it. This allows for greater encapsulation and reuse.

Often a framework can be used to create the dependency and inject it into client. Angular has Dependency Injection built right in and that's what I'm going to talk about today.

The Setup

I created a brand new project using the Angular CLI:


ng new InjectionExperiments

You should see the console chug for a bit:

This will create a new Angular application that we'll use as our base. I'm going to create a few components too:


ng generate component view1

And then


ng generate component view2

You'll see something like this:

I'm going to change the main display, app.component.html to include the two new components:


<app-view1></app-view1>
<br/>
<app-view2></app-view2>

Now you can run the app:

Load it in the browser:

If you've done any Angular development before, these are probably steps you've taken on.

Create a default Service

Now let's create a simple service which can be used to share data between the two components.


ng generate service services/service1

You'll see something like this:

We're ignoring the spec file for the purposes of these articles. Look at the service code:


import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class Service1Service {
constructor() { }
}

This is a standard TypeScript class, with one important distinction. It has an Angular decorator, Injectable, placed into it. This is the metadata that tells Angular to set this class up as a service. It also accepts an object config with the providedIn value. This value tells Angular to inject this service into the root module. Doing so will make this service available to all components in the application.

A service in Angular is a singleton. A single instance of the service class is created, and the same instance will be injected everywhere. This is what makes dependency injection so powerful. The same functionality and data can be shared among many different components, pipes, directives, and even other services.

Let's add a value into the service:


myValue = 'default';

To demonstrate how services work, we're going to share this value between both view1 and view2 and show that edits in view1 will automatically show up in view2.

Before we start on that, load the FormsModule into the main application. Open up app.module.ts and find the import section of the NgModule metadata. Add FormsModule:


imports: [
BrowserModule,
FormsModule
],

Be sure to import the FormsModule:


import {FormsModule} from '@angular/forms';

Now, let's open up the view1.component.ts. Find the constructor and modify it to look like this:


constructor(public service1: Service1Service) { }

You'll need to import the service here:


import {Service1Service} from '../services/service1.service';

This is the Angular dependency injection syntax at play. The variables in the constructor tell Angular to look for an instance of Service1Service and inject it into this component when it is created.

Open up view1.component.html and replace all the contents with this:


<h1>View 1</h1>
<input [(ngModel)]="service1.myValue">

We are using the ngModel directive with two way binding. When service1's myValue changes the input text will be updated. When the input changes, service1's myValue will update.

Now go to view2.component.ts ad inject service1 into the constructor using the same syntax that we used to inject it into view1:


constructor(public service1: Service1Service) { }

And you'll need to input the value here:


import {Service1Service} from '../services/service1.service';

Open view2.component.html and replace all its contents with this:


<h1>View 2</h1>
{{service1.myValue}}

Here we are just using Angular notation to evaluate the expression, in this case it just returns service1.myValue.

Now rerun the app and load it in the browser. You should see something like this:

Type in the input box from the view1 component and you'll see the output display in the view2 component.

Congratulations, you made your first service. By default, all your services are injected into the root module, but sometimes you don't need a global service, you just need a service for a specific section of the site, or maybe a single screen.

What's Next

You can play with the code here.

In the next article of this series, I'm going make some changes to the Injectable() metadata on the service, and see how that affects things.

How do I share a JWT Across multiple applications?

This question comes in from a reader.

Hi Jeffry, i read your articles at www.medium.com and like it a lot. Especially the article about "Combining Multiple Angular Applications into a Single One" .

So i got a question: Have you ever shared a jwt token between multiple angular applications? So that one login is enough. Like the setup you wrote in your article. Is this possible at all ? It would be nice to hearing from you :) Best regards Georg

Hi Georg,

Thanks for reading my articles from the Disney Streaming Services blog. I'm glad it helped you.

First, for the blog readers I wanted to explain what a JWT is. It is a Java Web Token, or rather some string that can be used to uniquely identify a user. In my work on one project, our JWT values are user objects, transformed to JSON, which are then encrypted and encoded for transport between the browser and server. Each respective request will need to decrypt and decode it to access the data.

Since you are building Angular applications, I assume you are storing the JWT value as a cookie. That's what I often do too.

If you have multiple applications--Angular or otherwise--delivered from the same web domain; they should all have access to that same cookie value and it should be sent to the server as part of every request you make, including REST service calls that most Angular applications use. Once that domain cookie is set, all your applications should be able to access it.

However, If your applications are on different web domains, you can probably create some server side code to generate the same token and send it to both applications based on the user login information. This would be an unusual setup, but I suspect is possible.

Good luck!

How do I give an Enum an object for a value?

The short answer is that you can't. Enums must be simple values. However, I found a creative work around that I quite like and I'm going to explain it here. If you haven't dealt with Enums a lot, check out my introductory post from last week.

The Problem

I recently wanted to use an object as the value for an enum. Let's pretend I am creating a hide and seek game. I have a bunch of characters that can be hidden:


export enum Character {
JEFFRY = 'Jeffry',
JOHNNY = 'Johnny',
JIMBO = 'Jimbo'
}

and a bunch of locations that a character can hide:


export enum Location {
LIBRARY = 'library',
SWAMP = 'swamp',
CASTLE = 'castle',
STUDY = 'study'
}

I wanted to create an enum for all possible places a character would hide. The object would look something like this:


export class HidingSpotVo {
character: Character;
location: Location;
}

And if I try to store a bunch of these object instances in an enum, it might be like this:


export enum HidingSpot {
JEFFRY_IN_LIBRARY = Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.LIBRARY});
JEFFRY_IN_CASTLE = Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.CASTLE});
JIMBO_IN_STUDY = Object.assign(new HidingSpotVo(), {character: Character.JIMBO, location: Location.STUDY})
}

I could add a lot more combinations here. This will cause all sorts of errors, because the value of an enum cannot be an object:

That doesn't help us solve our goal.

Create an Enum Class

My solution was to create a class that could give us similar functionality of the enum. Start with the class definition:


export class HidingSpot {
}

You've probably seen this a million times before. Now add a constructor:


private constructor(private hidingSpot: HidingSpotVo) {}

The constructor is marked as private. This is odd, but it prevents the consumers of this class from creating new instances of this. It is a trick that allows us to create a singleton. A hidingSpot value is passed into the constructor; and make private across the instance.

But, if the constructor is private, how do we create instances of this class? We do it from the inside the class:


static readonly JEFFRY_IN_LIBRARY = new HidingSpot(
Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.LIBRARY})
);

This is a static property, so we access the value on the class; not on an instance of the class. I also made the property read only so that it cannot be changed. We pass in an instance of the HidingSpotVo with the two cross sectional values, representing JEFFRY_IN_LIBRARY. We can use the same approach for some of our other values:


static readonly JEFFRY_IN_CASTLE = new HidingSpot(
Object.assign(new HidingSpotVo(), {character: Character.JEFFRY, location: Location.CASTLE})
);
static readonly JIMBO_IN_STUDY = new HidingSpot(
Object.assign(new HidingSpotVo(), {character: Character.JIMBO, location: Location.STUDY})
);

We can use this new class in the same way we can use an enum. First, an example of using it as the type of a variable:


private _hidingSpot: HidingSpot;

Then an example of using it as a return type for a function:


get hidingSpot(): HidingSpot {
return this._hidingSpot;
}

And finally, an example using it as an argument type for a method argument:


set hidingSpot(value: HidingSpot) {
this._hidingSpot = value;
}

We can set the value of this variable:


this.hidingSpot = HidingSpot.JEFFRY_IN_CASTLE;

And output it:


console.log(this.hidingSpot);

The output will give us an instance of the object.

Although, this isn't formally an enum, it is used in much the same manner and have a concrete list of non-editable values that can be referred used like a class and a constant at the same time.

What are Enums?

I've been working with Angular and Typescript for quite some time. They have a special data type called an Enum. This post will tell you all about them.

The Definition

An Enum is a data type where one value represents another valu. Enums are like a cross between a class and a constant. In TypeScript an enum looks like this:


export enum Character {
JEFFRY = 'Jeffry',
JOHNNY = 'Johnny',
JIMBO = 'Jimbo'
}

This character enum is a list of names. They have a controlled vocabulary of values under the same data type. This is how we might use an enum:

  • As the return type from a function
  • As an argument type into a function
  • As a variable type

We can demonstrate these pretty easily by creating a get / set property on a TypeScript class. First create a private variable:


private _character: Character;

This demonstrates using an enum as a variable type. Then create a get method:


get character(): Character {
return this._character;
}

This represents using an enum as the return type. The internal _character value is returned. Now, add a set method:


set character(value: Character) {
this._character = value;
}

This shows how you can use the enum as an argument into a function. You'll set the value something like this:


this.character = Character.JEFFRY;

which references one of the specific values in the Character enum. You can also output it:


console.log(this.character);

Which will give you the text value representing the enum. Enums can be powerful and I use them often when I need to represent a controlled vocabulary inside the angular apps I build.

Enum values must be primitive data types, such as strings, numbers, or boolean values. They cannot be objects. That is what I'm going to tackle next week.

Why is my Angular Linter throwing errors on private variables with underscores?

I was starting a new project on my local dev machine, and was creating a get set method inside an Angular class. It was something like this:


private _myFoo: string;
get myFoo(): string {
return this._myFoo;
}
set myFoo(value: string) {
this._myFoo = value;
}

This is a pretty standard implementation, however I noticed an error was showing on the first line:

The error was:

TSLint: variable name must be in lowerCamelCase, PascalCase or UPPER_CASE(variable-name)

I had never seen that before and the code still compiled, so what was going on here?

This was a linting error and to fix it I had to modify the linting settings for the project.

In the Angular project I opened up tslint.json file and added this rule to the end:


"variable-name": {
"options": [
"allow-leading-underscore"
]
}

Go here for more info on this variable-name linting rule.

Once I added this, linting started working as expected. I'm pretty surprised that the Angular linter was displaying this error by default.

Why won't my mat-select select items?

I'm working on an Angular project that includes a large legacy code base, and just spent a few hours trying to get a mat-select to actually select an item. No matter what I did it seemed like the selected item was always null. In case you're running into something similar, I'm going to show you how I fixed it.

First, I set up an Angular project and installed ng material.

Then, in a component, create a data provider:


dataSource = [
{label: 'one'},
{label: 'two'},
{label: 'three'},
{label: 'four'},
{label: 'five'},
{label: 'six'},
{label: 'seven'},
{label: 'eight'},
{label: 'nine'},
{label: 'ten'}
];

I just created a bunch of generic objects with a label property for the purposes of this sample. Also create a field to hold the selected value:


selectedItem;

Now, create your mat-select. Start with the mat-form-field:


<mat-form-field>
<!-- more stuff here -->
</mat-form-field>

Inside that mat-form-field place the


<mat-select placeholder="Select a Number" [(ngModel)]="selectedItem" >
<!-- more stuff here -->
</mat-select>

This is simple, it uses the ngModel to bind the selected item in the mat-select to the selectedItem property in the component class.

Now add the options:


<mat-option *ngFor="let item of dataSource" >
{{item.label}}
</mat-option>

This uses mat-option and loops over the data source to create the items. Run the code and you should see something like this:

Select an item and you'll see the placeholder stays the same:

Whenever I tired to access the selectedItem in code it was always null or blank. What was going on? Did you see my omission yet?

When creating the mat-options, they need a value:


<mat-option *ngFor="let item of dataSource" [value]="item" >
{{item.label}}
</mat-option>

Without these the mat-select has no idea how to match the selected item to an item in the data provider and the ngModel value will never get set. Once I put in the value everything started working again.

Play with the code here.

What is the new syntax for subscribing to Observables?

I was working on an Angular project, and noticed a warning when subscribing to an Observable. I had something like:


myObservableHere.subscribe((result: any) =>
{
console.log(result);
}, (err: any) => {
console.log(err);
});

I subscribe to the Observable, then put a comma separated list of methods. The first one is the next() method, and next comes the error() method, and finally we get a complete() method--left out of the sample above.

I've been using this syntax for what feels like forever, but today I was noticing a deprecated warning:

Use an observer instead of an error callback

I am using an Observable, why is this causing issues? First, it says to use an Observer, not an Observable. There is a distinction between them. The Observer is the value inside the Observable that is used to trigger the next, completed, or error messages. For most of my development this detail is hidden from me.

Instead of listing out each individual functions, we now can pass in an object and name them.

The new syntax would be like this:


myObservableHere.subscribe({
next: (result: any) =>
{
console.log(result);
},
error: (err: any) => {
console.log(err);
},
complete: () => {
console.log('complete');
}
});

The Observer that we pass in, is an object, and it contains three properties: next, error, and complete. Each one represents a function that will be triggered automatically from the observable.

If you drill into the code, you find some interesting things. In IntelliJ I just control-clicked on the subscribe() method to open up Observable.ts:


subscribe(observer?: PartialObserver<T>): Subscription;
/** @deprecated Use an observer instead of a complete callback */
subscribe(next: null | undefined, error: null | undefined, complete: () =>
void): Subscription;
/** @deprecated Use an observer instead of an error callback */
subscribe(next: null | undefined, error: (error: any) => void, complete?: () => void): Subscription;
/** @deprecated Use an observer instead of a complete callback */
subscribe(next: (value: T) => void, error: null | undefined, complete: () => void): Subscription;
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;

First, while three options are deprecated, the fourth one is not and our first syntax is okay. We only run into problems if the next, error, or complete function are null or undefined.

But, look at the first item int he list. The argument it expects is a PartialObserver; not an Observer. I control-clicked again to go to a types.ts file:


export type PartialObserver<T> = NextObserver<T> | ErrorObserver<T> | CompletionObserver<T>;

A PartialObserver is a union type, and can either be a NextObserver, ErrorObserver, or CompletionObserver. Each class definition includes a required method, and the remaining are optional:


export interface NextObserver<T> {
closed?: boolean;
next: (value: T) =>
void;
error?: (err: any) => void;
complete?: () => void;
}

export interface ErrorObserver<T> {
closed?: boolean;
next?: (value: T) => void;
error: (err: any) => void;
complete?: () => void;
}

export interface CompletionObserver<T> {
closed?: boolean;
next?: (value: T) => void;
error?: (err: any) => void;
complete: () => void;
}

The deprecated message was a bit confusing to dissect and solve, but by drilling into the code I was able to figure it out.

How do I Fix a TypeScript Version Mismatch when Upgrading to Angular 8

I recently upgraded a project from Angular 6 to Angular 8. I expected, primarily, this to go through with very few issues but did run into one. The Update Angular site gives a lot of great instructions, but they did not all go smoothly.

Specifically when trying to update the angular/core library I was getting an error similar to this:


Error: The Angular Compiler requires TypeScript >
=3.4.0 and <3.5.0, but 3.5.2 was found instead.

Migration can be rerun with "ng update @angular/core -from 7 to -8 --migrate-only"

First the command they said to use to rerun the upgrade failed. I opened up the package.json and saw this:


"typescript": "~3.4.5"

If the package.json tells me node to install 3.4.5, why was a later version installed? It took me a while to figure out what the problem was. The '~' before the version number means it can go higher, and in fact 3.5.2 was installed. I was able to address this by manually specifying a version number:


npm install typescriptg@">
=3.4.0 <3.5.0"

Then I reran the update script and things were solved.

More Entries

All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.