Check out our Angular Book Series.

Using `as type` - Type Assertions in TypeScript - Part 1

In an earlier article I wrote a bit about creating get/set properties in TypeScript. I am working on a project that uses a bunch of these, and sometimes they don't work.

Why do my get/set properties returned undefined? The method never executes, how can I fix it?

I'm going to show you why you're having problems and along the way talk about different forms of type conversions in TypeScript (and JavaScript).

The Setup

Let's start by creating a TypeScript class:


export class TestClass {
numbers: number[];
counter = 0;

get sum() {
this.counter++;
return this.numbers.reduce((accumulator, currentValue) =>
{
return accumulator + currentValue;
});
}
}

This class is named TestClass. It has three properties:

  • numbers: A regular property that contains an array of numbers
  • counter: A regular property that contains the number of the times that the sum was processed, perhaps a value you want to store for internal auditing purposes.
  • sum: A get property that returns the sum of all the values in the numbers array. Since this is a get property with no set, it is essentially read only and cannot set the value through traditional assignment.

Accessing a Get method with Simple JSON

When returning data from a server, I often get JSON, which is viewed as a generic object not tied to any specific TypeScript class. Look at code like this:


const testClassJSON = {numbers : [1, 2, 3, 4]};
console.log(testClassJSON.sum); // compile error

The first line hard codes a generic object, just like JSON that would be returned from the server to the application. this JSON matches the TestClass. But, the second line will give a compile error:

I can get this to compile if I tweak the code a bit differently:


const testClassJSON = {numbers : [1, 2, 3, 4]};
console.log(testClassJSON['sum']); // returns undefined

But, alas, that does not work, either:

The value is returned as undefined. The browser things this JSON value is a simple object:

There is no property named sum on a generic JavaScript object, and therefore cannot introspect special properties on the TestClass object.

For our get/set properties to work we need to perform some type of conversion from our generic JSON object to our formal type.

as TestClass

One version of Type assertion in TypeScript is similar to a cast that I've used in other languages.


const testClassAs = {numbers : [1, 2, 3, 4]} as TestClass;
console.log(testClassAs.sum); // returns undefined

Put this in your app and it should compile fine without any errors about the sum property not existing. That is progress. But, run the code and you see similar errors. The output to the console is undefined:

And the object in the debug tools is still seen as a generic object:

What gives? The `as type` is a TypeScript compile time assertion and has no affect at runtime. No conversion is made between your generic JSON class and your better typed TypeScript class. TypeScript does not even call this casting, because of the loosely typed nature of JavaScript. It calls it type assertion.

The angle bracket syntax of type assertion has the same problems.

For get/set properties to work, you must create an instance of that class somehow. I'm going to delve into that next week.

My Unit Tests are Running out of Order with Angular 8!

This is a weird one. I'm updating Unit Test from my LearnWith series for Angular 8. And I ran into a few tests that would inconsistently pass.

The app behind the LearnWith series is a task manager, and one of the tests that was failing was to mark a task completed.

Let's look at the test:


describe('completeTask() ', function () {
let task : TaskVO = {taskCategoryID:1,taskID:10,completed:true} as TaskVO;
};

This is a describe() block, for the completeTask() method and it also creates a default task.

I had two tests in this block. The first makes sure the task was completed:


it('Make task Completed', () =>
{
taskService.completeTask(task).subscribe(
value => {
expect(value.resultObject[0].completed).toBeTruthy();
});
const req = httpMock.expectOne(url) ;
req.flush({"resultObject":[task],"error":0});
}

I truncted it for simplicity. But, it takes the full task--defined as a constant in the describe block--passes that task into a service, creates a request, resolves it, and checks the value returned.

The same test suite had a test to mark a task not completE:


it('Make task Not Completed', () =>
{
task.completed = false;
taskService.completeTask(task).subscribe(
value => {
expect(value.resultObject[0].completed).toBeFalsy();
});
const req = httpMock.expectOne(url) ;
req.flush({"resultObject":[task],"error":0});
}

The second test sets the completed value on the task object to false; then runs very much the same code, and after the service is resolved; makes sure that the completed value is false.

The second test always ran without problems, but the first test would sporadically fail. My only explanation for this is that the tests must not be run in the same order on every execution of the test suite.

The task object is not reinitialized after every it() test, therefore the values can stay constant across multiple tests.

There are two solutions to this. The first is to make sure the first test sets the default value:


it('Make task Completed', () =>
{
task.completed = true;
// rest of test

That magically worked it.

The second solution is to move the task initialization into a beforeEach() block so it would be re-initialized before each test. That would look like this:


let task : TaskVO;

beforeEach(() =>
{
task = {taskCategoryID:1,taskID:10,completed:true} as TaskVO;
});

Either solution would solve the problem; and throughout my various tests I used one or the others depending upon what was failing.

Honestly, I'm surprised that this was not happening in versions of Angular prior to 8, so it took me a bit off guard.

Why can't Angular find the path() method on a Location object?

I'm writing some unit tests to test an Angular Router. In the test, I have code like this:


expect(location.path()).toBe('/something');

IntelliJ is giving me errors, saying it can't find the path value:

Clearly the path() method exists on the Angular Location object, so what was the cause of the error?

Apparently there is a JavaScript Location object.

The browser Location object does not contain a path() function even though the Angular one does.

Since Location exists natively, IntelliJ did not import the Angular library, and I didn't notice until I tried to run the code.

The fix is pretty simple. Just import the Angular Location library manually:


import {Location} from "@angular/common";

And you should be good to run your code and unit tests without any errors.

Angular 8 is Out

Angular 8 came out, and with it a new version of the Learn With Books.

I've gone through and updated everything. I've also added a brand new chapter to the Bonus book all about Angular Directives--that will be coming out soon.

Creating Angular Directives Part 5 - Applying One Directive to Different Elements

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2, and part 3 that discusses input properties, and Part 4 which covers event dispatching.

We have created a directive named reverse which will toggle CSS Between two separate states.

Using the Directive Multiple Times

All our samples so far have been applying the styles to the button, but we can easily use this same directive on other elements; here it is in a p tag and a div:


<p [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

The directive in a p!
</p>
<div [appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

The directive in a div!
</div>

The button is still in the view, and can be used to toggle:

Click the button and everything is reversed:

This is where we start to see the real power of encapsulating this in a directive. We are now writing simpler code than we would have if we were trying to do this using ngClass. Let's add four new styles into the create-attribute-directive.component.css:


.regular-red {
background: #ffffff;
color: #ff0000;
}

.reversed-red {
background: #ff0000;
color: #ffffff;
}

.regular-blue {
background: #ffffff;
color: #0000ff;
}

.reversed-blue {
background: #0000ff;
color: #ffffff;
}

The styles use red and white, or blue and white instead of our usual black and white. Apply them to HTML elements in create-attribute-directive-component.html:


<p [appReverse]="reversedState" regularCSSClass="regular-red" reversedCSSClass="reversed-red">
The directive in a p!
</p>

<div [appReverse]="reversedState" regularCSSClass="regular-blue" reversedCSSClass="reversed-blue">
The directive in a div!
</div>

The red style is applied to the p tag and the blue styles are applied to the div. Rerun the code:

And click to switch:

Final Thoughts

The bulk of Angular development I do is focused on creating custom components, not custom directives. But, understanding directives is important to being a good Angular developer because they give a different sort of flexibility that can be a benefit.

Be sure to check out my Learn With Series on Angular 8, which will cover this example in more detail, and even teach you all about Structural directives.

Creating Angular Directives Part 4 - Dispatching Events

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2, and part 3 that discusses input properties.

We have created a directive named reverse which will toggle CSS Between two separate states.

Dispatching Events

A directive can dispatch its own events, just like a component can. Let's add an event to the directive that will dispatch whenever the state changes. First, I'll add a new class:


export class CSSReversedEvent {
addedCSSClass: string;
removedCSSClass: string;
}

I put this class in the reverse.directive.ts file, instead of creating its own class file. It includes one value for the CSS Class that was removed, and one for the CSS Class that was added.

Now inside the ReverseDirective class, add the output event:


@Output() stateChange: EventEmitter<CSSReversedEvent> = new EventEmitter();

This uses the @Output() metadata to create the EventEmitter named stateChange. How look at the changeState() method:


changeState() {
const newState: CSSReversedEvent = new CSSReversedEvent();
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, this.regularCSSClass);
this.renderer.addClass(this.el.nativeElement, this.reversedCSSClass);
newState.addedCSSClass = this.reversedCSSClass;
newState.removedCSSClass = this.regularCSSClass;
} else {
this.renderer.removeClass(this.el.nativeElement, this.reversedCSSClass);
this.renderer.addClass(this.el.nativeElement, this.regularCSSClass);
newState.addedCSSClass = this.regularCSSClass;
newState.removedCSSClass = this.reversedCSSClass;
}
this.stateChange.emit(newState);

The first line in the method creates a new instance of the CSSReversedEvent class. The middle of the method will add the CSS Values onto this new object, depending on which state we are entering. The final name of the method will dispatch the event.

Open up the create-attribute-directive.html file and add in the stateChange event listener:


<button (click)="reverseState()"
[appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed"
(stateChange)="onStateChange($event)">

Reverse State
</button>
The event listener will call the onStateChange() event inside the create-attribute-directive.component.ts file:


onStateChange(event) {
console.log(event);
}

For simplicity I just outputted the event to the console.

Rerun the code and start clicking buttons:

During component initialization this event is dispatched twice. Once after the reversedState value is set, but before the regularCSSClass and reversedCSSClass are set. We see the event dispatching undefined for each class in this case. Then it is dispatched a second time after the initialization is complete. This is when the initial styles are applied to the button.

Click the button a few times to see the events continue to dispatch:

At this point in the series, you should realize that there is a lot you can do with directives.

What's Next?

For the last article in this series, I'm going to give a sample of applying the same directive to different elements.

Creating Angular Directives Part 3 - Exposing Properties

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to include a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive and part 2 that introduces the renderer2.

We created a directive named reverse which will toggle CSS Between two separate states.

Expose New Properties

The directive as is is hard coding the style values inside the directive. That is horrible use of encapsulation, and limits reuse. Let's open those up. Open up reverse.directive.ts:


@Input() regularCSSClass: string;
@Input() reversedCSSClass: string;

I added one input for the regularCSSClass and one for the reversedCSSClass. Now move to the changeState() function:


changeState() {
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, this.regularCSSClass);
this.renderer.addClass(this.el.nativeElement, this.reversedCSSClass);
} else {
this.renderer.removeClass(this.el.nativeElement, this.reversedCSSClass);
this.renderer.addClass(this.el.nativeElement, this.regularCSSClass);
}
}

Instead of accessing hard coded values as the CSS Class is added, or removed, from the native element the variables are added.

Notice how the values have no default styles. To solve that we'll make sure to call the changeState() method when ngOnInit() runs, which will be after the property values are set. First implement the OnInit interface as part of the class definition:


export class ReverseDirective implements OnInit {

Then add the ngOnInit() method:


ngOnInit() {
this.changeState();
}

This will make sure that the default states are set after the component is initialized. Open up create-attribute-directive.component.html and add in our two new properties:


<button (click)="reverseState()"
[appReverse]="reversedState"
regularCSSClass="regular"
reversedCSSClass="reversed">

Reverse State
</button>

Angular's magic under the hood will know the new attributes belong to the directive and will pass in those values.

Rerun the app:

Then click the button:

The new Angular directive inputs were set up as regular HTML attributes with string values, but we could set them up as Angular attributes with an Angular expression as the value. In the simplest form, like this:


<button (click)="reverseState()"
[appReverse]="reversedState"
[regularCSSClass]="'regular'"
[reversedCSSClass]="'reversed'">

Reverse State
</button>

The Angular expression is a literal string, and the regularCSSClass and reversedCSSClass are enclosed in brackets, signifying they are properties.

What's Next?

The next part of this series will show you how to use events as part of a directive.

Creating Angular Directives Part 2 - Using Renderer2

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to do a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

Check out Part 1, with project setup and a starter directive. We created a directive named reverse which will toggle CSS Between two separate states.

Using Renderer

If you read the docs on the ElementRef's nativeElement property, there is a big warning to avoid using it. It breaks encapsulation by accessing the DOM directly, and can lead to unexpected results in the application.

We're going to use the Renderer2 component instead. It is designed to give a layer of abstraction between Angular and the DOM within directives like this. While we're at it, I'm also going to switch to using a CSS Class instead of accessing styles directly.

The first step is to inject the Renderer2 into the directive's reverse.directive.ts file:


constructor(private renderer: Renderer2, private el: ElementRef) { }

The reversedState property remains unchanged, but we will want to modify the changeState() method. This is the current method:


changeState() {
if (this.reversedState) {
this.el.nativeElement.style.backgroundColor = '#000000';
this.el.nativeElement.style.color = '#ffffff';
} else {
this.el.nativeElement.style.backgroundColor = '#ffffff';
this.el.nativeElement.style.color = '#000000';
}
}

This uses the nativeElement to change the DOM directly. Widely considered a bad a practice.

Change it to use the renderer2 to add and remove classes:


changeState() {
if (this.reversedState) {
this.renderer.removeClass(this.el.nativeElement, 'regular');
this.renderer.addClass(this.el.nativeElement, 'reversed');
} else {
this.renderer.removeClass(this.el.nativeElement, 'reversed');
this.renderer.addClass(this.el.nativeElement, 'regular');
}
}

Instead of drilling down into the nativeElement directly, we're calling the addClass() and removeClass() methods on the renderer, and passing in the nativeElement along with the new style. We could have done the same thing with the previous sample, using addStyle() and removeStyle() methods on the renderer.

Let's be sure to add our regular and reversed styles to create-attribute-directive.css:


.regular {
background: #ffffff;
color: #000000;
}

.reversed {
background: #000000;
color: #ffffff;
}

Rerun the code:

Then click the button:

There are no change from the previous implementation, we just have a different, better, implementation under the hood.

What's Next?

Part 3 of this series will show you how to use properties in your component so that you do not have to hard code styles inside it.

Creating Angular Directives Part 1 - A Simple Directive to Toggle State

I'm updating my Learn With tutorial books that teach Angular Development for Angular 8. I decided to do a deep dive into Angular Directives. This series of posts is a snippet of what will be in the full series, and is focused on creating attribute directives.

What is an Angular Directive?

An Angular directive is just like an Angular component, except with no template. A directive can be applied to any HTML Tag or template. There are two types of directives:

  • Attribute: An Attribute directive will apply something to an existing HTML Element, or even your own Angular component.
  • Structural: A Structural directive will modify the HTML body by creating, or removing, elements.

This series of posts will focus on creating an attribute directive.

Setup

First, create a new project with the Angular CLI:


ng new

You can follow through the instructions at your discretion, but you'll go through a wizard like this:

I named the project ud, for Understanding Directives. I set up routing and used regular CSS.

In the app.component.html file, delete everything except the router-outlet, so the file looks like this:


<router-outlet></router-outlet>

You can run the app, but you won't see much until we start adding routes.

Create the Attribute Directive

We're going to create a directive that will toggle an HTML Element between two separate visual states, done by changing different CSS elements on the directive.

First, we'll do some setup. Create a component for creating our own attribute directive:


ng generate component create-attribute-directive

You'll see something like this:

Open up the app-routing.module.ts file and a sample2 route to the Routes array:


const routes: Routes = [
{path: 'sample2', component: CreateAttributeDirectiveComponent},
{ path: '**', redirectTo: '/sample2'}
];

Now, use the Angular CLI to create our first directive:


ng generate directive directives/reverse

You'll see something like this:

I put the new directive in the directive directory. If nothing is specified it will be put in src/app by default, but long term I like to keep my code better organized without a lot of things in the main app directory. Open up the reverse.directive.ts:


import { Directive } from '@angular/core';
@Directive({
selector: '[appReverse]'
})
export class ReverseDirective {
constructor() { }
}

First, we import the Directive class. This is metadata used to define the directive. The only thing we define, at this point in the metadata is the selector. We'll use this when we apply the directive to an HTML element, the Angular module, something like this:


<button appReverse></button>

Right now, the directive doesn't do anything, but we'll come back to this in the HTML template later. It is strongly recommended you do not name your custom directives with a prefix ng because that is used by the Angular framework and we want to avoid conflicts with other existing directives.

I want to note that the directive is loaded in the main Angular module. Open up app.module.ts and you'll see it in the declarations section:


@NgModule({
declarations: [
AppComponent,
UseAttributeDirectiveComponent,
CreateAttributeDirectiveComponent,
ReverseDirective
],
// other stuff
})

If you do not add your directive to the @NgModule your app won't know how to find it and you'll get compiler errors.

The first thing we want to do is inject the ElementRef into the directive class:


constructor(private el: ElementRef) { }

Dependency Injection for Directives works just like it does for other components, so we inject the value into the constructor. This will give the directive class a reference to the component which is was placed on.

This directive needs to pass in a value of the directive name, and then make changes to the ElementRef's styles based on that. To do that we'll need to define an Input() metadata. The simplest way to do this:


@Input('appReverse') reversedState: Boolean;

When the directive sees the appReverse directive applied to an HTML tag as an attribute, the value will be set in the reversedState value inside the directive class. In order to run some code whenever that value changes I'm going to switch it to a get/set method:


private _reversedState = false;
@Input('appReverse')
get reversedState() {
return this._reversedState;
}
set reversedState(input) {
this._reversedState = input;
this.changeState();
}

The get and set methods are pretty standard. A private variable holds the state. The get method will return that private variable, and the set method will set it. The set method also runs a changeState() method, so let's look at that:


changeState() {
if (this.reversedState) {
this.el.nativeElement.style.backgroundColor = '#000000';
this.el.nativeElement.style.color = '#ffffff';
} else {
this.el.nativeElement.style.backgroundColor = '#ffffff';
this.el.nativeElement.style.color = '#000000';
}
}

This method checks the reversedState value and sets the background and foreground colors. I use nativeElement property on the ElementRef to drill down into the component and set specific styles. For the moment, I'm hard coding the color values, but we'll revisit that in a later sample.

How do we use the directive? Open the create-attribute-directive.component.html file:


<button (click)="reverseState()" [appReverse]="reversedState">
Reverse State
</button>

The appReverse directive is placed directly on the button; and it is given the value of reversedState, which is a Boolean value in the component that we'll create. The click button is used to call a reverseState() method that will toggle the reversedState property.

Open the create-attribute-directive.ts file. First create the reversedState property:


reversedState = false;

Then add the reverseState() method:


reverseState() {
this.reversedState = !this.reversedState;
}

We've seen this method, and property, set up identically in the previous sample. The major change is in how the new styles are applied to the button.

Rerun the app:

Click the button and the state should switch:

Play with it to switch the state back and forth.

Congratulations you did it!

What's Next?

While this is a simple example, it does show that we can create our own directive and use it to affect the HTML element is is applied to. This type of example is pretty common when you search for directive tutorials throughout the web, however by accessing the nativeElement directively it creates a dependency between your directive and the internals of Angular which may change.

The next article in this series will show you how to address this using the Angular renderer.

How do I redirect to a different domain inside Angular?

I was doing a code review for a colleague,and as part of his code he was redirecting the browser:


window.location.href = "http://www.google.com";

This code was working perfectly fine, but when performing a redirect to another domain in an Angular component, there is a `more angular` way to make this work by using the Document service.

First import this:


import {DOCUMENT} from '@angular/common';

Then you need to inject that into your component:


constructor(
@Inject(DOCUMENT) private document: Document
) {}

This inject syntax is a bit different than a normal Angular service because it uses the Inject metadata.

Once the document is injected, you can redirect like this:


this.document.location.href = 'http://www.google.com';

This is just an Angular layer of abstraction over the native JS way to perform a redirect; but when working within an Angular component I like to lean on the Angular abstractions. They help with unit testing purposes.

Get the code here.

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.