Communicate between controllers in Angular by using a simple pubsub service in TypeScript.

 

I created a really simple angular PubSubService in TypeScript, to allow communication between controllers or directives or services.

 

In the example below, controller 1, fires an event and controller 2 reacts to the firing of the event.

 

 

module dev {
    "use strict";

    var appModule = angular.module("myApp", []);

    appModule.controller("MyController1", ["$scope", "pubSubService", ($scope, pubSubService)

    => new dev.MyController1($scope, pubSubService)]);

    appModule.controller("MyController2", ["$scope", "pubSubService", ($scope, pubSubService)
    => new dev.MyController2($scope, pubSubService)]);

    

 

    export class MyController1 {
        constructor(public $scope: ng.IScope, public pubSubService: PubSubService) {
            // Fire an an event
            pubSubService.publish("my-custom-event", "some publisher data");
            }
    }

    export class MyController2 {
        constructor(public $scope: ng.IScope, public pubSubService: PubSubService) {
            this.handleMyCustomEvent = this.handleMyCustomEvent.bind(this);

            // Subscribe to be notified, when "my-custom-event" is fired.
            pubSubService.subscribe("my-custom-event", this.handleMyCustomEvent);
        }
   
        handleMyCustomEvent(data: any) {
        // Do something, when an event is fired from MyController1.
        }
    }

 

    /**
     * This service can be used to share data between controllers by using a pub sub mechanism.
     */
    export class PubSubService {
        private nextListenerIndex: number;
        private listeners: Array<IListener>;

        constructor() {
            this.listeners = [];
            this.nextListenerIndex = 0; // The first subscription will be located at index 0;

            this.publish = this.publish.bind(this);
            this.subscribe = this.subscribe.bind(this);
            this.unsubscribe = this.unsubscribe.bind(this);
        }

        /**
         * Publish an event.
         * All subscribers will be notified.
         * @param name, is the name of the event and is case insensitive.
         */
        publish(name: string, data?: any) {
            for (var i = 0, length = this.listeners.length; i < length; i++) {
                const listener = this.listeners[i];
                if (listener && listener.name.toLowerCase() === name.toLowerCase()) {
                    listener.handler.call(null, data, listener.subData);
                }
            }
        }

        /**
         * Subscribe to be notified, when an event is published.
         * @param name, is the name of the event and is case insensitive.
         * @returns A token, that can be used to unsubscribe.
         */
        subscribe(name: string, handler: (data?: any, subData?: any) => void, data?: any): number {
            var token = this.nextListenerIndex;
           
            this.listeners[token] = {
                handler: handler,
                name: name,
                subData: data
            };
            this.nextListenerIndex += 1;

            return token;
        }

        /**
         * Remove the event listener subscription.
         * @param token received on subscribing to an event listener.
         */
        unsubscribe(token: number) {

            // This will create holes in the array, but for now we do not care.
            this.listeners[token] = null; 
        }
    }

    export interface IListener {
        // This function will be called when an event is published.
        // Data is the data from the publisher, subData is the data from the subscriber.
        handler: (data?: any, subData?: any) => void;
        name: string;
        subData?: any; // Data from the subscriber.
    }

    angular.service("pubSubService", () => new PubSubService());
}

Fix: Visual Studio doesn’t use or can’t find TypeScript typings (*.d.ts) in a .net core project

 

I added some TypeScripts typings to a .net core project in Visual Studio 2015  (version 14.0.25123.00 Update 2), by using the NPM package “typings”, but the added *.d.ts files, were not picked up by Visual Studio, this was caused by excluding the “wwwroot” folder in the tsconfig.json,

 

after removing the wwwroot folder from the exclude array, the typings were correctly found and used.

 

 

 

{
  "compileOnSave": true,
  "compilerOptions": {
    "module": "system",
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es6"
  },
  "exclude": [
    "node_modules",

     "wwwroot" <========================= Remove the wwwroot
  ]
}

Some nice new features are coming to TypeScript

 

npm for type definition files

One of the things that annoyed me was the tsd tool for installing type definition files.

Why can’t I just use npm, for installing type definition files. I use npm for installing external libraries en tooling so why not type definition files.

 

Well they are working on just that, kudos to the TypeScript thing.

 

Non nullable types

An other thing is non nullable types, I certainly want to have that in TypeScript.

It will be possible to tell the compiler, a certain variable is a string and not null or undefined. But you can also write: const x : string | null which means, x is a string or null but not undefined.

 

Down level async await support

TypeScript code which uses async await can target ES5

 

http://video.ch9.ms/ch9/4ae3/062c336d-9cf0-498f-ae9a-582b87954ae3/B881_mid.mp4

Yes: Cycle.js is getting some TypeScript love

 

In his blog post: http://staltz.com/all-js-libraries-should-be-authored-in-typescript.html mentions:

I am a JavaScript programmer, and I make some libraries. Recently, however, I’ve been writing TypeScript for RxJS version 5 (used in Angular 2 which is also authored in TypeScript),

and I’m in the process of rewriting Cycle.js in TypeScript.

I find the cycle.js framework very interesting and I love to see it written in TypeScript, so kudo’s for André Staltz, when he accomplishes this.

Starting with ASP.NET 5, TypeScript 1.7 and the ES6 module syntax compiled to ES5.

In the previous post I described how you can get started with ASP.NET 5.

 

The code used in this blog post can be found at: https://github.com/roelvanlisdonk/Research/tree/master/Blog/ASP.NET5/TypeScriptES6Modules

 

In this post I will describe how you can get start using TypeScript 1.7 and the ES6 module syntax to order your code in an ASP.NET 5 application.

 

I will explain how you can use a “library” module inside your app code, by using TypeScript and the ES6 module syntax.

The compiled code will be in ES5, so we need a library called “system.js” to load the “ES6 modules” at runtime.

 

  • After you followed the steps in the previous post
  • Add a TypeScript JSON Configuration File to the wwwroot folder

 

image

 

Add "module": "system", under compileroptions:

 

image

 

Add two typescript files:

  • wwwroot/core/app.ts
  • wwwroot/libraries/list/findIndexByItem.ts

image

 

 

 

  • Add the system.js bower package.

This is needed, because the typescript will be compiled into javascript modules.

These modules are in the “system.require” format.

We could use other module formats (see tsconfig.json), but in this example I wanted to use system.js

 

Before we can add the system.js bower package, add a “Bower Configuration File” to the root of the project.

 

image

 

In this example I use the folder “wwwroot/libraries” to store all my runtime JavaScript dependencies, so we have to edit the .bowerrc file, change:{ “directory”: “wwwroot/lib” } to { “directory”: “wwwroot/libraries” } .

 

image

 

Now we can install the system.js bower package:

 

image

 

 

findIndexByItem.ts

 

image

 

 

app.ts

 

image

 

 

index.html

 

The only javascript file we directly load in the index.html is “/libraries/system.js/dist/system.js”. All other logic will be dynamically loaded by the system.js loader.

 

To  make system.js recognize file paths like System.register(["../libraries/list/findIndexByItem"] , so without the “*.js” extension, we need to add a little configuration by using System.config, then we load the “core/app.js” file and start the application.

The “core/app.js” uses the library module “findIndexByItem.js”. This JavaScript file will be dynamically loaded, when “core/app.js” is requested.

 

 

image

 

Result

 

image

 

 

Note: for browsers that do not support promises you need a promise polyfill, that can be found, here: https://github.com/jakearchibald/es6-promise/

Fix: TypeScript 1.7.6 compile on save in Visual Studio 2015 not working

I upgraded Visual Studio 2015 TypeScript extension to 1.7.6, then compile on save stopped working.

First I checked if “Compile on save” was enabled on my 4.5.2 web project properties (TypeScript Build tab):

 

image

 

Then I checked if “Automatically compile TypeScript file which are not part of a project” was enabled (Tools / Options).

 

image

 

Then the TypeScript files still would not compile on save (they were compiled, when the project was build, but not when a TypeScript file was saved.

 

The solution

I removed the following part in my Web.csproj file:

 

<PropertyGroup Condition="’$(Configuration)|$(Platform)’ == ‘Debug|AnyCPU’">
    <TypeScriptTarget>ES5</TypeScriptTarget>
    <TypeScriptJSXEmit>None</TypeScriptJSXEmit>
    <TypeScriptCompileOnSaveEnabled>True</TypeScriptCompileOnSaveEnabled>
    <TypeScriptNoImplicitAny>False</TypeScriptNoImplicitAny>
    <TypeScriptModuleKind>None</TypeScriptModuleKind>
    <TypeScriptRemoveComments>False</TypeScriptRemoveComments>
    <TypeScriptOutFile />
    <TypeScriptOutDir />
    <TypeScriptGeneratesDeclarations>False</TypeScriptGeneratesDeclarations>
    <TypeScriptNoEmitOnError>False</TypeScriptNoEmitOnError>
    <TypeScriptSourceMap>True</TypeScriptSourceMap>
    <TypeScriptMapRoot />
    <TypeScriptSourceRoot />
  </PropertyGroup>

 

Then I added a tsconfig.json file to the root of my project:

image

 

tsconfig.json

{
  "compilerOptions": {
    "noImplicitAny": true,
    "sourceMap": true,
    "target": "es5"
  }
}

 

 

 

Don’t now if both steps are needed, but after that, my compile on save started working again.

How to get full class name, including module name from an instance at runtime in TypeScript

Let’s assume we have the class [GuidGenerator] in a TypeScript module [research.my.long.namespace] and at runtime you have an instance of the GuidGenerator, how do you get the full class name including module name, in this case: “research.my.long.namespace.GuidGenerator”.

Well you walk the object graph starting with the root / global object, in the browser this will be the window object.

 

NOTE: all code is in “strict” modus.

 

TypeScript Class [GuidGenerator]:

module research.my.long.namespace {
"use strict";
export interface IGuidGenerator {
generate(): string;
}
export class GuidGenerator implements IGuidGenerator {
generate() {
var randomNumberToGuid = function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : r & 0x3 | 0x8;
return v.toString(16);
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, randomNumberToGuid);
}
}
}

We use the resolver object to get the full class name:

var resolver = new NameResolver();
var generator = new research.my.long.namespace.GuidGenerator();
var name = resolver.getFullClassNameFromInstance(generator, window)
console.log(name);

Result

image

The resolver class

module research.metadata {
"use strict";
interface IProcessResult {
fnFound: boolean;
path: Array<string>;
}
export interface INameResolver {
getFullClassNameFromInstance(instance: any, global: any): string;
}
export class NameResolver implements INameResolver {
private _fn: any;
private _global: any;
private _processed: Array<any>;
/**
To handle recursiveness in the object graph, collect all handled nodes in the object graph,
so an object is only traversed once.
*/
isProcessed(obj: any): boolean {
var result = false;
for (var i, length; i < length; i += 1) {
if (this._processed[i] === obj) {
return true;
}
}
return result;
}
processProperty(obj: any, key: string, path: Array<string>): IProcessResult {
var result: IProcessResult = {
fnFound: false,
path: path
}
if (obj.hasOwnProperty(key)) {
try {
var prop = obj[key];
if (prop === this._fn) {
// Function found, stop traversing the object graph.
result.fnFound = true;
return result;
}
// Continue traversing the object graph.
result = this.processObject(prop, path);
if (result.fnFound) {
// Function found, stop traversing the object graph.
return result;
}
} catch (error) {
// Access to some properties result in exceptions.
}
}
return result;
}
processObject(obj: any, path: Array<string>): IProcessResult {
var result: IProcessResult = {
fnFound: false,
path: path
}
if (this.isProcessed(obj)) {
return result;
}
this._processed.push(obj);
for (var key in obj) {
var pathCopy = path.slice();
pathCopy.push(key);
var processResult = this.processProperty(obj, key, pathCopy);
if (processResult.fnFound) {
return processResult;
}
}
return processResult;
}
getFullClassNameFromInstance(instance: any, global: any): string {
this._fn = instance["constructor"];
this._global = global;
this._processed = [];
var processResult = this.processObject(this._global, []);
var fullFnName = "";
if (processResult.fnFound) {
fullFnName = processResult.path.join(".");
}
return fullFnName;
}
}
}

Running javascript and typescript unit tests in Microsoft Visual Studio 2012 with Chutzpah

To unit test my JavaScript files in Microsoft Visual Studio 2012, side by side mine C# unit tests, I use Chutzpah.

Chutzpah comes with 2 Microsoft Visual Studio 2012 extensions:

1. Chutzpah Test Adapter for Visual Studio 2012, allows you to run QUnit / Jasmine javascript test files side by side C# unit tests in the test explorer or continuous build process.

2. Chutzpah – A JavaScript Test Runner, allows you to run individual QUnit / Jasmine JavaScript test files in Microsoft Visual Studio 2010 and 2012 by right clicking a test file and choosing "".

 

In Microsoft Visual Studio 2012

– Tools > Extensions and Updates…

– Install both plugins and restart Microsoft Visual Studio 2012

 

image

 

Create a new UnitTest project:

 

image

 

Enable "Run Tests after build"

(The "Play" button found at the top of the Test Explorer")

Now when you press CTRL + SHIFT + B the project will be build and all tests will execute.

 

image 

 

TIP: Never use CTRL + S to save your file, just use CTRL + SHIFT + B.

Now you can see the C# unit test "TestMethod1" succeeded.

 

QUnit for ASP.NET MVC

Right click unit test project and click Manage NuGet Packages…

Click install.

 

image

 

Add Code.js and Test.js

The Code.js file will contain the JavaScript code we want to test.

The Test.js  file will contain the JavaScript test code written, by using the QUnit test framework.

 

Code.js

image

 

Test.js

Reference qunit and the Code.js file to get code completion in your test code.

 

image

 

Code completion in JavaScript in Microsoft Visual Studio 2012 unit test file

 

image

 

 

Run C# and JavaScript unit tests side by side in the Test Explorer

By pressing CTRL + SHIFT + B

image

 

Run only JavaScript unit test file

If you only want to run the QUnit test, right click on the JavaScript Test.js file and choose "Run JS Tests".

 

image

 

If you want to run JavaScript unit tests by pressing a keyboard shortcut, you need to install

image

 

Then you can bind a shortcut to the ProjectAndSolutionsContextMenus.Project.RunJSTests command to run JS tests.

(http://matthewmanela.com/blog/chutzpah-1-1-0-released/)

 

image