Check out our Angular Book Series.

How do I set a Custom Header on an Angular HttpClientTestingModule Test?

In a few other posts I wrote about how to access custom headers in an Angular GET HTTP call and how to set custom headers in an Angular PUT or POST call.

But, how do I test those methods creating a custom header? It isn't hard.

Let's assume I'm trying to test code like this:


let mySavedCustomHeader;
makeServiceCall(): Observable<object | MyCustomClass> {
return this.http.get(`url`, { observe: 'response' })
map((response: HttpResponse<object>) =>
{
// save header
mySavedCustomHeader = response.headers.get('my-custom-header-name');

// other processing as needed
Object.assign(new MyCustomClass(), response.body)
return myCustomResponse;
})
}

There is a method, presumably on a service. It makes a service call to some service and passes in a configuration object that says "return the response. The result handler accesses the header object in order to get our custom header returned from the service. Then it does other processing. this should be relatively straight forward.

So, how do we test this?

First, set up your TestBed, be sure to load the HttpClientTestingModule:


let service, httpMock;

beforeEach(async(() =>
{
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule
],
providers: [
MyCustomService,
]
}).compileComponents()
.then (() => {
service = TestBed.get(MyCustomService
httpMock = TestBed.get(HttpTestingController);
});
}));

This code saves the service and httpMock values for later use in our test.

Start the test:


it('should call REST Endpoint with custom header', () =>
{
// all our other code will go here
});

First thing we want to do is make the service method. It returns an Observable so we'll subscribe to it and add some tests.


service.makeServiceCall().subscribe((value) =>
{
expect(service.mySavedCustomHeader).toBe('something');
});

Inside the service result handle we check for the custom header value on the service and make sure it was set. The assertions inside the result handler will run as the last piece of this method, even though the come first. Nothing has triggered the result handler yet.

How look for the mock HTTP call


const request = httpMock.expectOne('url');

I'll often run some assertions on the requestt


expect(request.method).toEqual('get');

Now create an HTTPHeader object:


const HttpHeader = {}
HttpHeader['my-custom-header-name'] = 'something';

And finally, flush the HTTP call:


req.flush(SomeCustomObjectWeDidNotCreateHere, {
headers: new HttpHraders(HttpHeader)
});

And that should be all you need to pass your custom header to the from your test into your service code.

How can I set headers in an Angular POST or PUT request?

In my previous article I spoke about accessing HTTP header values in an Angular GET request. Now, I'm going to show you how to set them as part of an HTTP PUT or POST request.

A simple update, might go something like this:


saveItem(item: ItemClas): Observable<Item> {
return this.http.put(`url`, item)
.pipe(
map(response =>
{
// process response
return response
})
);
}

We call a simple http.put() give it the URL and the item w are updating is the body. We process, and return the results. All good; this works great.

But, what happens when we want to send a custom header to the request? There is third parameter to a put() or post() call . It is a configuration object, and we can include our headers in there.

First, create the header:


const headerObject = {};
headerObject['my-header-name'] = my-header-value;

Then create the configuration object, with a headers property, that has the value of HttpHeaders object.


return this.http.put(`url`, item, {headers: new HttpHeaders(headerObject),})

That's all you need to properly add the header to the service call.

How can I prevent an image from being dragged in my browser?

I've been doing some work on an Angular project with Dragula. I disabled our draggable div under certain conditions, but our users were still able to drag an image that lied within the Dragula div. Dragula prevented the drop, so our data was not put in a comprimising state, but it was confusing to our users that they could drag soemthing and not drop it.

Once I disabled Dragula on the div, the users were making use of default browser functionality. How can I prevent that?

There doesn't seem to be an easy cross browser way to do it, so I had to implement a few solutions.

First, for Chrome, I was able to use some CSS.


.no-drag{
-webkit-user-drag: none;
}

This web kit specific CSS extension prevents the item from being dragged.

Apply it to your imagE:


<img src="something" class="no-drag" />

But that did not solve the issue in Firefox. To do that I had to add the draggable attribute.


<img src="something" class="no-drag" draggable="false"/>

At this point it worked in both Firefox and Chrome and I stopped testing.

How do I use a compareWith Function with Angular Material?

In this screencast I talk about using a compareWith function with Angular Material.

Find the original vid on YouTube and check out the source on GitHub

How do I test nativeElement.focus in Angular?

In last week's post I wrote about setting focus on an element with Angular.

This week I wanted to write tests behind that code.

A Review

First, let's review what we want to test. We have a loop of inputs in the HTML Template and access them in the component class using the ViewChildren() metadata:


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

Then we have an onClick() method which accepts an input and determines which element to set focus too:


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

As a good developer, I of course, want to write tests against that onClick() method.

Write the Tests

If you're building off last week's project, you can open up the app.component.spec.ts file. You probably already have a beforeEach() which creates the basic application. Let's add a new describe block to the file:


describe('onClick()', () =>
{
});

Good start, let's add some variables:


let app;
const e1: ElementRef = new ElementRef({focus() {} } );
const e2: ElementRef = new ElementRef({focus() {} } );

I created one app variable to reference the component, and two ElementRef constants. When creating an ElementRef we pass in a nativeElement object. For the purposes of this test, I created a mock object with a focus() method. In production code I would have formalized a mock class to represent a nativeElement.

Now, let's add a beforeEach:


beforeEach(() =>
{
});
</code>

Nothing interesting here. Inside the beforeEach() let's get access to the app:

<code
const fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;

This gets access to the fixture and saves the app for future use. Now detectChanges():


fixture.detectChanges();

This forces the component to render once, which will create all the viewChildren and populate the inputs variable.

Now, add spys for the focus method on our custom elementRef objects:


spyOn(e1.nativeElement, 'focus');
spyOn(e2.nativeElement, 'focus');

Our code will check on these spys to make sure the appropriate element was focused on based on our inputs in the onClick() method.

I want to do one more spy:


spyOn(app.inputs, 'toArray').and.returnValue([e1, e2]);

When our onClick() method tries to convert the inputs into an array, this gives us complete control over what the onClick() method is accessing. Even though the elements in the view are properly rendered, using this spy with controlled return values gives us granular control over the test.

Now let's write a test:


it('should call focus on element 0', () =>
{
app.onClick(0);
expect(e1.nativeElement.focus).toHaveBeenCalled();
expect(e2.nativeElement.focus).not.toHaveBeenCalled();
});

This call s the onClick() method with a 0 index. It verifies that focus was called on e1, but not on e2.

We can write a second test using a different index value:


it('should call focus on element 1', () =>
{
app.onClick(1);
expect(e1.nativeElement.focus).not.toHaveBeenCalled();
expect(e2.nativeElement.focus).toHaveBeenCalled();
});

This calls the same onClick() method, with a different index, and swaps the checks making sure that focus() was called on the e2 element and not the e1 element.

Run the code:

Success!

That is one way to test how to set focus on an element using Angular.

Play with the code here

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 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.

Component Specific Providers - Dependency Injection and Angular - Part 4

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.

Component specific providers

Everything we've built in the previous examples has shown how providers work when created at the root level. You can also create providers at the component level. This can be common if you have split up your app into sections which are lazy loaded. One section may need to know nothing about the other section, and thus you don't need a global service, just one specific to that section. In other cases, you may just need to share some data, or functionality, across all the components that make up a specific screen. That is what I'm going to demo now.

Let's create a brand new service:


ng generate service services/service4

You'll see this:

Open up the service class:


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

First, we're going to remove the providedIn metadata. Second, we're going to add a shared value in this service:


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

Since we no longer specify providedIn value to be root, we must set up this component as a provider. In past examples we did this with a module, however, we can also use the same metadata in a component.

Open up view1.component.ts and find the Component metadata. It'll look like this:


@Component({
selector: 'app-view1',
templateUrl: './view1.component.html',
styleUrls: ['./view1.component.css']
})

Add a providers array to this component:


@Component({
selector: 'app-view1',
templateUrl: './view1.component.html',
styleUrls: ['./view1.component.css'],
providers: [Service4Service]
})

Components support the same providers array syntax that our app module is. The main difference is where the service instance is maintained. In this case the provider will be specific to this component. Be sure to import the Service4Service class:


import {Service4Service} from '../services/service4.service';

And inject the new service into the constructor:


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

Switch over to the view1.component.html file and add this at the end:


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

This uses the ngModel to bind the input value to the value inside the services. In past examples we used this approach to share services across multiple components. Let's see how it goes here.

Onto the view2.component.ts. We're going to mirror our changes from the view1.component.ts. First, add Service4 as a provider:


@Component({
selector: 'app-view2',
templateUrl: './view2.component.html',
styleUrls: ['./view2.component.css'],
providers: [Service4Service]
})

Then inject the provider into the constructor, along with all the services from our previous samples:


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

Be sure to properly import the Service4Services class:


import {Service4Service} from '../services/service4.service';

Switch over to view2.component.html and output the value at the bottom:


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

Now run the app:

Notice that updating the service4 value in view1 has no affect on the output in view2. This is because each component is creating its own instance of the service because the provider is set up at the component level, something that both of these components do not share.

What Next?

You can play with the code here.

In the next article of this series, coming out in a few weeks, I'm going to talk about how to create multiple Angular service providers using the same exact class. I ran into this in a real world sample, and the approach was not as trivial as I expected it to be.

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.