Being forward compatible – Goodbye SASS hello CSSNext

Instead of being backwards compatible we want to be forward compatible.

But what do I mean with “forward compatible”?

Well that’s when we write our code against the next standard spec, but compile down to older specs to be backwards compatible, so for example:

 

TypeScript

 

We use TypeScript to write modern ES6, ES7, ES8 code, but we compile down to ES5 to be backwards compatible with older browsers.

 

CSSNext

 

The only reason we used SASS in the current project, was to re-use color variables in css.

Now the css next spec includes custom properties (variables), so to be forward compatible we decided to port our SASS to CSSNext.

 

CSSNext with PostCSS

 

PostCSS is a node package that can be installed by using NPM, it can be used to pre-process CSS by using JavaScript / TypeScript.

One of the many plugins of PostCSS is een CSSNext plugin, in the following example I will be using this plugin to convert CSSNext code into normal CSS3 code.

In this example I will be using Visual Studio 2015 update 3.

 

 

Create a new MVC web project

 

File > New > Project…
Installed > Templates > Visual C# > Web > ASP.NET Web Application (.NET Framework) > MVC

 

Add a package.json file to the root of the web application

 

{

“dependencies”: {
“angular”: “1.2.29”,

“es5-shim”: “>=4.5.9”,

“es6-shim”: “>=0.35.1”,

“spin.js”: “>=2.3.2”

},
“devDependencies”: {

“del”: “>=2.2.1”,

“gulp”: “>=3.9.1”,

“gulp-debug”: “>=2.1.2”,

“gulp-postcss”: “>=6.1.1”,

“gulp-rename”: “>=1.2.2”,

“gulp-util”: “>=3.0.7”,

“postcss-import”: “>=8.1.2”,

“postcss-cssnext”: “>=2.7.0”

},
“name”: “WebApplication1”,

“private”: true,

“scripts”: {

“gulp”: “gulp”

},
“version”: “1.0.1”

}

 

Add a gulpfile.js to the root of the web application

 

/**

* The version of gulp and all it’s dependencies are managed in the package.json file.

*/

‘use strict’;

// Dependencies

const gulp = require(‘gulp’);

const postcss = require(‘gulp-postcss’);

const postcssImport = require(‘postcss-import’);

const postcssNext = require(‘postcss-cssnext’);

const rename = require(‘gulp-rename’);

const defaultTheme = ‘Stigas’;

/**

* The default task.

*/

gulp.task(‘default’, function () {

});

gulp.task(‘apply-theming’, function () {


var plugins = [

postcssImport,

postcssNext

];


return gulp.src(‘./Content/Site.cssnext’)

.pipe(postcss(plugins))

.pipe(rename({

extname: “.css”

}))

.pipe(gulp.dest(‘./Content’));

});

Add a “Content/variables.cssnext” file

 

:root {


–mainColor: rgb(255, 0, 0);

}

 

Rename the existing Site.css to Site.cssnext

 

At the following text at the top of the Site.cssnext file: @import
“./variables.cssnext”;

And at the following css rule at the end of this script:

p {


color: var(–mainColor);

}

Now run the gulp task “apply-theming” by using the Task Runner Explorer or on the command line: npm run gulp — apply-theming

 


 

 

Now when you run the web application you should see the text in red:


 

 


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());
}

Autofill issues: This is the first time, Chrome disappoints me

When I set the attribute “autocomplete” to the value “off” on a form element, I expect Chrome, to NOT autofill fields in the form, but that’s not the case.

 

Even if you also add the autocomplete attribute to the input element with value “off”, this is not the case.

 

To get it working I had to add autocomplete=”off” to the form tag and add autocomplete=”new-password” to the <input type=”password” /> field.

How to use angular in a fancybox dynamically shown by jquery

In a brownfield application I encountered a old fancybox jquery plugin. This plugin was used throughout the whole application. This fancybox is just a modal dialog.

I wanted the content of the fancybox to be handled by angular.

 

To accomplish this, I used the following code:

 

image

 

 

You can find the code at:

 

https://github.com/roelvanlisdonk/Research/tree/master/Base/Web/src/Web/wwwroot/blog/fancybox

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
  ]
}

Yes, Yes–Integrated Terminal in Visual Studio Code

 

The killer feature I was missing in Visual Studio Code was a integrated terminal.

 

More and more I use the command line for all kinds of tasks, but I don’t want to leave my editor, so I’m very glad that the visual studio code team decided to create a integrated terminal, currently it can only by found in the insiders builds, but a stable release containing the integrated terminal is on it’ s way.

 

To open the integrated terminal hit CTRL + `.

 

Event the shortcut is convenient Smile.

 

So to install all the npm packages in your project just hit CTRL + ` and enter npm install:

 

image

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