Check out our Angular Book Series.

How do I set focus on an HTML element with Angular?

I've been working on a project where we wanted to load a screen and set it to the default state. It isn't that hard to do with Angular. This will show you how.

Set up a Basic Project

I started by creating a default Angular project with ng new. This will run you through the wizard and create a default component. For the purposes of this sample we're going to just modify the default component, app.component.

You can run the project using ng serve.

Create the Inputs

In a real world app there are plenty of ways to create your inputs. For the sake of this, we're going to create a bunch of inputs in a loop. Open up the app.component.html file:


<div *ngFor="let x of [0, 1, 2, 3, 4]">
<b>Input {{x}}</b>: <input #input> <button (click)="onClick(x)">Set Focus</button><br/>
</div>

The code uses ngFor to loop over an array. We give each input a label and a button. The button calls a method named onClick() which will give focus to the correct input.

Set focus on a click

Open up the app.component.ts file. First step is to get access to the ViewChildren:


@ViewChildren('input') inputs: QueryList<ElementRef>;

The input string in the ViewChildren() metadata refers to the #input text in the HTML input. Since we are referring to an array of inputs we use ViewChildren and QueryList instead of ViewChild and ElementRef. The QueryList is sort of like an array of all the HTML elements.

Now, create the onClick() method:


onClick(index) {
this.inputs.toArray()[index].nativeElement.focus();
}

The argument into the method is an index, referring to the item we want to put focus on. The method converts the QueryList inputs into an array using the toArray() method. Then it references the specific element using the index, accesses the nativeElement. The nativeElement references the actual HTML DOM element and is only supposed to be used or accessed sparingly. Finally, call the focus() method on the nativeElement.

We should be good to go.

Run the Code

Run the code in a browser. You should see something like this:

Click the buttons on the right and you should see focus being set to the proper input:

Now you know how to set focus on an input within Angular.

Play with the code here

Next week I'm going to show you how to test the onClick() method

How do I map a Keyboard character on the Surface Laptop?

My wife's computer died. She got my Surface Book and I got a brand new Surface Laptop 3. To date, my experience is significantly nicer than using a Surface Book on release day. Maybe I'll have a more in depth post about it later.

I'm setting up a Surface Laptop 3, and once again There is no right control key. But, there is a menu key next to the arrows that should have been a control. As a writer I almost always use control-right and control-left to pagination through words in a sentence. It works in word and in my web browser and everywhere else and was the primary reason I could never acclimate to using an OSX computer.

Anyway, I want to remap the key, so how do I do it? There is this great tool called SharpKeys to help. Get it from here, or grab the code from GitHub.

Launch the program:

Click the add button:

Click Type Key button on the left half of the screen. Now tap the 'menu' key on the keyboard. You should see something like this:

Click okay.

On the right side of the screen, find the "Special - Right Ctrl" option and select it. You can't select it from the keyboard since it isn't on the Surface Laptop's keyboard.

Click okay, and you should see your new mapping in the list. Click 'write to registry' and the app will tell you that you need to logout for it to take affect.

Logout or restart your computer and you'll be good to go.

In other news, why would anyone ever need a dedicated key to bring up the context menu?

Happy New Year

The new year is often a time to look back and look forward, but I'm honestly not sure what to say about 2019. Let's see what comes out.

Books and Writing

DotComIt has continued to chug along in a stable position. I continue to write and publish books in the Learn With series and that is the primary focus of DotComIt right now, but I still take on consulting projects as they come up, so if you have something I can help with don't hesitate to reach out.

I'm a quarter of a way through a book focused on RXJS, an Observable library used heavily in Angular. The progress is not nearly as quick as I had hoped, but it is moving along. I keep restructuring the chapters to avoid interrelated dependencies. I haven't found the time and energy to push this thing out, unfortunately. Writer updates are boring, so I'll spare you all the details.

I continue to post weekly on my personal blog--right here. I published 53 posts in 2019. In 2020, I expect to pull back on my weekly publishing schedule so I can focus on redoing the blog design in order to make it more mobile friendly and easier to navigate.

Projects

I don't often talk about specifics of my projects, because I'm often bound by different legal documents that prevent me from sharing specifics. But you may have noticed that I contributed a bunch of blog posts to the Disney Streaming Services blog. They had a big launch last year and I'm part of the team that built some back-end tools. It has been the most high-profile, public, launch I've ever been involved in.

Music

On a personal note, I continue to write and record music, and want to increase that in 2020. The balance helps me keep my mind fresh and stave off any burn out from all the programming and writing. I broke my first drumsticks 2 months ago laying down the track for a new song which I'm really excited about. I've also been experimenting with some video recordings of some live performances. If anything happens with this stuff, I'll post about it here, even if it is not the tech content you signed up for.

Final Thoughts

That is about it for me. I'm planning a trip to Star Wars Galaxy Edge shortly, and hope to have a more relaxing vacation at some future point.

Turning off Comments

I had 10,000 un-moderated spam comments in my queue to review. I deleted them all, and turned off commenting for all posts. The time for discussion based on blog comments is primarily passed us anyway. This is something I may look into tackling in 2020, but for now I'm fine with keeping things as is.

How to watch the Active Element in Chrome?

I put together a video for how to watch the Active Element of a web page in Chrome Developer tools. This has become useful when writing CSS with lots of embedded elements.

How to I access URL.createObjectURL() in an Angular App?

I've been working in a project where we accessing the browser's URL object in order to use createObjectURL() to download a file created in the browser.

This is an Angular app, because that is often what I work on. It is often considered a best practice to not access global browser variables, but rather to access global elements through Angular injection.

If you're using a normal JavaScript app, you can access URL using the window object, like this.


console.log(window.URL);

But, there is no built in way to inject window into an Angular App.

So, I started looking into using a Document injection to reference the Window object. This is unusual because usually the Document is a child of Window, so I wasn't sure if the reverse relationship would be there.

But, it is. Here's how to do it.

First, inject the Document:


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

This uses slightly more complex syntax than a standard injector, because you specify the @Inject() metadata here and use the DOCUMENT injector token.

Once you have that you can access the window object from the document using defaultView:


console.log(this.document.defaultView);

And once you have the defaultView or Window object, you can drill down into it to access the URL object:


const myURL = this.document.defaultView.URL.createObjectURL(myObjectToCreateUrlFor));

This worked well for us, giving us access to the global window object / URL functionality, without breaking encapsulation of our Angular service that needed to access these values.

How do I reload the current route in an Angular Application?

I've been going through some writers block lately, so I'm trying to blast it by doing a screencast instead. This is how you can reload the current route in an Angular Application.

Create Two Services from One Class - Dependency Injection and Angular - Part 5

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 previous entries:

  1. The one where we set up a project and create a default Angular Service
  2. The one where we remove the providedIn configuration object
  3. The one where we remove all the injectable metadata
  4. Component Specific Providers

Create Two Services from One Class

I had an issue come up during some recent development. Two sections of an application needed to store settings, each using an identical class structure. However, the two settings could not be mixed, so I could use the same service for each. I wanted to create two separate services, using the same class. Since our main navigation would need to access these respective services, I could just inject these values at a component level. The answer was to create my own injection token, and inject the components slightly differently. I'll explain that here.

First, let's create the class. I didn't use the Angular CLI for this one. I just created a class named service5.service.ts:


export class Service5Service {
myValue = 'default 5';
constructor() { }
}

This follows a similar approach to services we created earlier.

Now open up the app.module.ts:


export const SERVICE5_VIEW1 = new InjectionToken<Service5Service>('Service5View1');
export const SERVICE5_VIEW2 = new InjectionToken<Service5Service>('Service5View2');

This uses the Angular InjectionToken class to create two separate instances of an injectable Service5Service. Be sure to import the InjectionToken:


import {InjectionToken, NgModule} from '@angular/core';

And the Service5Service:


import {Service5Service} from './services/service5.service';

Next, we need to tell the @NgModule to use these InjectionTokens to create a new service. We do that as part of the providers array:


providers: [
Service2Service,
Service3Service,
{ provide: SERVICE5_VIEW1, useValue: new Service5Service()},
{ provide: SERVICE5_VIEW2, useValue: new Service5Service()}
],

Instead of listing a specific class in the providers array, we are providing a configuration object. The first value, provider, tells us about the service, and in this case we are specifying the InjectorToken we shared as a constant. The second property, useValue, tells us the value to use when this InjectionToken is referenced. In this case, we created a new instance of the Service5Service.

The injection syntax into a component is a bit different. Let's inject it as part of the constructor of view1.component.ts:


@Inject(forwardRef(() =>
SERVICE5_VIEW1)) @Optional() public service5: Service5Service

Be sure to import the inject and forwardRef metadata:


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

And Service5Service:


import {Service5Service} from '../services/service5.service';

And the injector constant:


import {SERVICE5_VIEW1} from '../app.module';

What does this code do? The Inject metadata tells Angular not to perform a lookup for a specific class, but rather to look for this specific injector in order to get the appropriate value. The forwardRef function tells Angular to populate this value after it is defined. In certain cases, this value may not be set up before the view is initialized, so this makes sure Angular will set it up after the fact.

Once this is injected, we use it just like we would use any other class. Open up view1.component.html:


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

As with some of our past examples, we added an input that will change myValue inside service5.

Now open up view2.component.ts. We want to follow the same path, but with the other injector token. Add the injection to the constructor:


@Inject(forwardRef(() =>
SERVICE5_VIEW2)) public service5: Service5Service

This follows the same approach from the previous sample. Be sure to import the Inject metadata:


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

The SERVICES5_VIEW2 constant:


import {SERVICE5_VIEW2} from '../app.module';

And the Services5Serivce class:


import {Service5Service} from '../services/service5.service';

The code for injecting SERVICES5_VIEW2 into view2 works identically as the code for injecting SERVICES5_VIEW1 into view 1.

Now open view2.component.html, and the output display from Service 5:


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

If we've set this up right View 1 service5 and View 2 service5 instances are completely independent, and changing one will not change the other.

Run the app and test:

You'll see that edits in view1 have no affect on edits in view2, because we have completely different services even if they use the same backend class.

What Next?

You can play with the code here.

This is the end of my exploration into Angular Dependency Injection. You should have a good understanding of how to create a service, how to inject--either using the providedIn configuration object or the providers array--and how to make the service specific to a single component.

Jasmine Comparison Showdown: toEqual() vs toBe()

I was doing a code review for a colleague recently and noticed his test used toEquals() to compare two separate arrays. Wait! What? You can't do that? I checked out the code and stepped through it using IntelliJ's debugger. Indeed the code did work. I needed to find out what toEquals() was! Up until then, I'd primarily focused on toBe() for comparisons in unit tests. When I needed to compare an array or array items, I'd often dig deep and compare individual elements, or properties on such elements. I'm a bit embarrassed I never knew there was a better / easier way. Let's look at toEqual() along with a dose of ToBe().

Which is Which?

  • >toBe(): The toBe() comparison will compare two references. If they are equal, you'll get a success and if not, you'll get a failure. It uses `===` under the hood.
  • >toEqual(): The toEqual() compares values in the object. It is a deep equality comparison.

For simple values, both toBe() and toEquals() are essentially identical. toEqual() becomes much more interesting when dealing with objects, or arrays.

Object Comparison

Object Comparisons are pretty easy to set up in a test. First, create the test outline:


it('Should compare Objects', () =>
{
});

Now, create two objects in the test:


const obj1 = {id: 1, foo: 'bar'};
const obj2 = {id: 1, foo: 'bar'};

We have two objects, and therefore two object instances, but the properties and values inside each object are identical.

Run these two assertions:


expect(obj1).not.toBe(obj2); // reference compare; not equal
expect(obj1).toEqual(obj2); // property compare; equal

The toBe() comparison checks for references. Both obj3 and obj4 are pointed at different objects, and as such the compare will fail. I added a not to the compare so it would succeed.

The toEquals() comparison will check the values in each object. Since they match up, and all have equivalent values on each property, it passes.

If there is any difference between the properties of the two objects the toEquals() compare will fail. Let's add a third object:


const obj3 = {id: 1, foo: 'bar', foo2: 'bar2'};

And a new assertion:


expect(obj1).not.toEqual(obj3); // property compare; not equal

Since the third object has a new property, the two objects are not comparatively equal.

Array Comparison

This use case is more interesting to me. You can use toEqual to compare the objects in two separate arrays.

As with the previous sample, let's start with two objects:


const obj1 = {id: 1, foo: 'bar'};
const obj2 = {id: 2, foo: 'bar2'};

And create two arrays from these objects:


const array1 = [obj1, obj2];
const array2 = [obj1, obj2];

Each array is different, but has the exact same objects in the exact same order.

Normally in a situation like this I'd drill down into the array elements, possibly accessing specific properties to determine equality:


expect(array1[1]).toBe(array2[1]); // reference compare, equal

It works, but is not the most elegant way.

Comparing the two arrays with toBe() will cause a failed assertion:


expect(array1).not.toBe(array2); // reference compare; not equal

I make this pass by using the 'not' operator. Using toEqual() on the other hand succeeds:


expect(array1).toEqual(array2); // element compare; same references, equal

That is awesome.

The order of elements in the array must be equal. We can add another array:


const array3 = [obj2, obj1];

It contains the same objects, but in the reverse order. The comparison will fail:


expect(array1).not.toEqual(array3); // element array; different order, not equal

The equals() comparison is drilling down into objects for specific values. In the array it is not comparing references.

Let's create a third object:


const obj3 = {id: 1, foo: 'bar'};

The 3rd object is the same as our first object, in terms of values. Let's also add a fourth array:


const array4 = [obj3, obj2];

The fourth array is different from array1, in that it references a different array instance, and in the fact that the first element is a different object. However, since obj3 and obj1 are similar, we can still compare with toEquals() succesfully:


expect(array1).toEqual(array4);

I can definitely see using this in future tests more than I have in the past.

I threw together some samples using Angular, because that was the TypeScript framework I had easily available to set up some quick experimental tests.

Check out the code sample.

How to Spy on a Private Method with a Jasmine

I was writing some tests for an Angular project. I was testing a public method, but that public method called a private method which returned some an Observable. I wanted to spy on the method, and control the returned Observable, so I could test the internal subscribe() results. Trying to spy on the private method in the usual way caused issues. This post will explain the issues and how I got around it.

The Setup

For the purposes of this sample, you can find the code in this repo. But if you want to follow along and build from scratch, I started by creating a new Angular project with the Angular CLI.

Then I opened up the `app.component.ts` project. Create one private method:


private myPrivateMethod(value) {
return value;
}

And create one public method:


myPublicMethod(value) {
return this.myPrivateMethod(value);
}

This demonstrates a public method calling the private method, which is enough for the purposes of this sample.

Write the Broken Spy

The first step in testing an Angular application is to create the TestBed, which is done by default with the Angular CLI, so we can move onto our test:


it('should spy on method', () =>
{
const fixture = TestBed.createComponent(AppComponent);
const app: AppComponent = fixture.debugElement.componentInstance;
});

Get the fixture, and then an instance of the AppComponent. If you're not using Angular as a framework, the syntax will probably be as simple as:


const myClass = new MyClass();

Now, add a spy. Normally I'd do something like this:


spyOn(app, 'myMethod');

Your IDe will probably show you an error:

The solution is to add an `` distinguisher to remove the error:


const privateSpy = spyOn<any>(app, 'myPrivateMethod');

Now, you can call your public method:


const returnValue = app.myPublicMethod('something');

And then call your assertions. There are a handful of different ways to check the spy. This would be the easiest:


expect(app['myPrivateMethod']).toHaveBeenCalled();

Instead of using object property notation to make sure the method was called, we use array notation with a literal string. This is because private methods don't exist in JavaScript. This notation gets around the TypeScript compile warnings that would occur of we tried to access `app.myPrivateMethod()`.

You can also check the myPrivateSpy variable directly:


expect(privateSpy).toHaveBeenCalled();

This works great, and is identical to the previous line.

You could also drill into the spy object:


expect(privateSpy.calls.any()).toBeTruthy();

Although, my usual mode of operation would be to use the first two methods.

spyOn with will work just like a spy on without it. So you can return values, or callThrough when creating the spy. Or you could use any of the various spy tests, such as `toHaveBeenCalledWith()`, `toHaveBeenCalledTimes()`, or others.

You can play with 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.