Check out our Angular Book Series.

Using Angular, RXJS, and SystemJS

just updated DotComIt's build scripts for building Angular 6 applications. I wrote these before the AngularCLI was king of the heap and keep these around because I haven't had time to update my LearnWith series, which contains an introduction to Angular.

Anyway, I copied my Angular5 scripts, updated the package.json to a bunch of new versions, build the sample app, and then started getting errors from the application:


Error: Unexpected token <
Evaluating http://local10.dciseed.dot-com-it.com/Angular6TypeScript/build/js/rxjs

My local dev server has directory browsing turned on, so instead of loading the actual files behind rxjs it was trying to load the directory listing. That won't work. I also saw this error in my experimentation, which said that '"rxjs/operators" not found'. Supposedly that issue was fixed long before RXJS 6.0.0, but alas I was still seeing it.

The solution was to list all the rxjs directories as a package inside of SystemJS Config:


packages: {
'rxjs/ajax': {main: 'index.js', defaultExtension: 'js' },
'rxjs/operators': {main: 'index.js', defaultExtension: 'js' },
'rxjs/testing': {main: 'index.js', defaultExtension: 'js' },
'rxjs/websocket': {main: 'index.js', defaultExtension: 'js' },
rxjs: { main: 'index.js', defaultExtension: 'js' }
}

It took me a while to find this solution, and even then I couldn't get it to work until I removed the quotes around the last package definition.

Weird stuff,

How do you Access the Arguments of a Jasmine spy?

I've been writing unit tests for clients. It's a nice change to finally have some clients who care about such things.

I have this Angular method that creates an object, then emits an event.

The method was something like this:


onButtonClick() {

let eventParameters = {};

// do stuff

this.eventEmitter.emit(eventParameters);
}

I want to be compare the properties of the eventParameters argument with what I expect them to be. However, I have no way to access the eventParameters directly because it is local to the method. My first thought was to do something like this:


spyOn(component,'onButtonClick').and.returnValue(myOwnEventParametersObject)

However my intent was to test the code inside the method, whereas this bypasses calling the method altogether. That would not suffice.

So, how'd I do it?

First, I saved an instance to the Spy:


const mySpy = spyOn(component.eventEmitter, 'emit');

I can drill down into this spy to get the results of the most recent call:


const recentCallArgs = mySpy.calls.mostRecent().args[0];

Once I have the argument object, I can introspect it to compare the arguments created by the method with what I expected them to be.


expect(recentCallArgs.value).toBe('value');

TaDa!

How do I combine Objects in JavaScript? Use the Ellipsis Operator!

This is a followup to last week's post about using Object.assign() to combine two JavaScript objects. Today I'll show you how to use the spread, or ellipsis, operator to do the same thing.

The scenario is that we have a configuration object being passed into a method. A lot of the config values are optional, and we want to default them if they are left out before the method does it's magic. We could write a lot of manual conditions to accomplish this, like this:


function conditionalConfig(config){
if(!config.option1){
config.option1 = defaultOption1Value;
}
if(!config.option2){
config.option2 = defaultOption2Value;
}
// etc.. etc.. etc..
// do other stuff
}

The code works, but it is tedious to write. We can use the Spread Operator to simplify it.

The Spread Operator

The spread operator is an ellipsis, or three dots. It has a handful of uses, but today I'm going to show you how to combine two objects.

Start with a function and an object that contains all the default values:


function defaultConfigWithSpread(config){
defaultObject = {
option1 : 'DefaultValue1',
option2 : 'DefaultValue2',
option3 : 'DefaultValue3',
option4 : 'DefaultValue4',

Notice I didn't close the object yet. We have one more property to add to the object:


...config
}

That last property is our spread operator. It tells the underlying engine to take all the properties from the config object and copy them into the defaultObject. If a property already exists in the defaultObject, it is overwritten. If a property does not exist it will not be changed.

For demonstration purposes, log the two objects:


console.log(config);
console.log(defaultConfig);
// do other stuff
// end function
}

You can test this like this:


customConfigObject = {
option1 : 'Value1',
option2 : 'Value2',
option3 : 'Value3',
}
defaultConfigWithSpread(customConfigObject);

Look at the console output and you'll see that the original config object is unchanged, but the default object contains all the new values:

The custom values from our config argument are retained and the unset default value--option4--is set with the new config.

You have to be careful when doing this to keep around a clean version of the default object since it is modified with this approach. I addressed that by creating the default config inside the function, as opposed to some permanent store.

Play with the code here.

It is a nice shorthand to be aware about.

How do I combine Objects in JavaScript? Use object.assign()!

Let's say we have a config object being passed into a method. A lot of the config values are optional, and we want to default them if they are left out before the method does it's magic. The structure is like this:


function conditionalConfig(config){
if(!config.option1){
config.option1 = defaultOption1Value;
}
if(!config.option2){
config.option2 = defaultOption2Value;
}
// etc.. etc.. etc..
// do other stuff
}

The code works great, but it is tedious to write all those conditionals. Is there a way to simplify it? Yes there is and I'm going to talk about two ways to do that. Today we'll cover object.assign().

Object Assign

The first way to simplify this code is to use object.assign(). Object.assign() will copy all the values from one object into another. First, create an object instance with all the default values:


function defaultConfigWithAssign(config){
defaultObject = {
option1 : 'DefaultValue1',
option2 : 'DefaultValue2',
option3 : 'DefaultValue3',
option4 : 'DefaultValue4',
}

Now use Object.assign() to combine that with your function argument:


Object.assign(defaultConfig,config)
// dump to console for testing purposes
console.log(config);
console.log(defaultConfig);
// do other stuff
// end function
}

You can test this like this:


customConfigObject = {
option1 : 'Value1',
option2 : 'Value2',
option3 : 'Value3',
}
defaultConfigWithAssign(customConfigObject);

Look at the console output and you'll see that the original config object is unchanged, but the default object contains all the new values:

The custom values from our config argument are retained and the unset default value--option4--is set with the new config.

You have to be careful when doing this to keep around a clean version of the default object since it is modified with this approach. I addressed that by creating the default config inside the function, as opposed to some permanent store.

Play with the code here.

Next week I'm going to talk about the Spread operator which can be used to accomplish the same thing.

How do I test Observable.timer?

This was trickier than I thought, which is why I'm writing a blog post about it. I'm writing some code which uses an FakeAsync Zone nor RxJS TestScheduler.

The timer() call returns an Observable, so I decided to create one myself which gave me complete control.


let timerObserver :Observer<any>;
beforeEach(() =>
{
spyOn(Observable, 'timer').and.returnValue(Observable.create(
(observer =>{
timerObserver = observer;
})
));
});

I created an Observer object. This is the internal logic that makes the Observable resolve itself. I used spyOn() inside a beforeEach() to have the unit testing framework return my own Observable and ignore the library code. I save the observer for later usage.

Now, when I'm testing I can resolve the timer immediately:


it('Some Test',()=>
{
// do stuff if needed

// trigger the fake timer using the Observer reference
timerObserver.next('');
timerObserver.complete();

//
expect(somethingToHappenAfterTimerCompletes).toHaveBeenCalled();
});

I spent more time banging my head on this than I thought I would, and I hope this helps you.

How do I listen for an Angular Event in TypeScript?

I'm building a custom Angular service for a client project that will create modal and other popups. If certain interaction occurs within the modal, then the modal should dispatch an event and the service needs to close the modal. In Angular you can use an EventEmitter to dispatch the event from the component's class. Create the emitter as a property on the component's class and add the @output metadata:


@Output()
myEvent : EventEmitter<any> = new EventEmitter();

Then to dispatch the event use the emit method:


this.myEvent.emit('Emitted Value');

That does exactly what I need in the component side. However, to listen for the event, most of the documentation I can find talks about doing so in the HTML template:


<MyComp
(myEvent)="onMyEvent($event)">

</MyComp>

Unfortunately, the service cannot add that event handler onto HTML because there is no HTML, so that was a no go for my use case. How do you do it?

After the service creates the component and displays it, it has an instance to that component class. We can introspect into the component class to get access to the emitter, and subscribe to it:


myCompRef.instance.myEvent.subscribe((value) =>
{
// do something
});

Under the hood the EventEmitter is a Subject, which is like an Observable.

Running Unit Tests from IntelliJ

I put together this screencast about running Unit Tests using IntelliJ.

How do you tell Jasmine to run a single test?

Last week I wrote about how to tell Jasmine to ignore a unit test. This week I'll tell you how to ignore every unit test except one.

To use last week's example, a normal unit test would be something like this:


it("True is True", () =>
{
expect("True").toBe("True");
});

A normal test suite will include lots of tests spread out through lots of files. You can focus a unit test using fit(). This tells Jasmine to only run the unit test with the 'f':


fit("True is True", () =>
{
expect("True").toBe("True");
});

other unit tests will be ignored. This can be a great use when testing something new.

You can use the same thing to disable a full suite with fdescribe() instead of describe:


fdescribe("Some Test Suite"()=>
{
it("True is True", () =>{
expect("True").toBe("True");
});
});

This type of stuff can be pretty handy if you're running your tests via command lines.

How do I tell Jasmine to ignore a test?

Today I learned you can tell Jasmine to ignore a unit test. A normal unit test would be something like this:


it("True is True", () =>
{
expect("True").toBe("True");
});

When running a unit test file with this inside the test will run., You could comment it out if you wish, but that can get confusing for larger unit tests with embedded oomments. Instead you can use xit() instead of it():


xit("True is True", () =>
{
expect("True").toBe("True");
});

Now when you run your unit test, this test will be marked as viewed as pending and will not be run.

You can use the same thing to disable a full suite with describe():


xdescribe("Some Test Suite"()=>
{
it("True is True", () =>{
expect("True").toBe("True");
});
});

This is pretty handy, but something I overlooked when learning all about unit testing.

How to I make my Angular Component Styles global?

An awesome thing about building Angular components is that the styles you specify are 'local' to the component.

In normal HTML development, any style on the page can affect any other style. For example. If I add a style like this:


div {
border:1px solid red;
}

Every div in the site / application will have a solid red border. Check out a sample here.

If you build an Angular, component, and that style is only included in the application as part of the component, then only that component's div will given a solid color red border.

The reason for this is because Angular creates something they call a Shadow DOM. Under the hood it is some coding magic to conditionally apply styles only to the component in question, not to other components.

However, Angular allows us to change this behavior using something called ViewEncapsulation.

A default Angular component is like this:


@Component({
selector: 'my-comp',
templateUrl: 'my-comp.component.html',
styles: [`my-comp.component.css`],
encapsulation: ViewEncapsulation.Emulated
})

The Emulated value means that Angular will simulate a Shadow DOM. This is considered safest because not all browsers support their own shadow DOM trees.

In most cases, I use this approach and leave out the encapsulation attribute. I like to have my styles encapsulated to a single component. But that is not required. There are two other options:


@Component({
selector: 'my-comp',
templateUrl: 'my-comp.component.html',
styles: [`my-comp.component.css`],
encapsulation: ViewEncapsulation.Native
})

The Native property tells Angular to use the browsers Shadow DOM. In this case, styles are encapsulated just like they would be in the emulated approach. So, any styles in the my-com-componment.css file will affect all HTML elements globally.

To turn off style encapsulation complete, use the None value from the ViewEncapsulationclass:


@Component({
selector: 'my-comp',
templateUrl: 'my-comp.component.html',
styles: [`my-comp.component.css`],
encapsulation: ViewEncapsulation.None
})

I'm working on my second super really big Angular application for a client, and it is giving me the opportunity to touch on areas I normally wouldn't.

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.