MobX and TypeScript Experiement

I wanted to give MobX a try, in particular from TypeScript.

Here’s my first attempt. I liberally used the documentation example found within createTransformer as my guide.


import "core-js";
import { observable, autorun, createTransformer } from "mobx";

/*
 The store that holds our domain: boxes and arrows
*/

class Store implements Storable {
 @observable public boxes: Box[];
 @observable public arrows: Arrow[];
 @observable public selection: any;

 constructor(init: Storable = {}) {
     this.boxes = init.boxes || [];
     this.arrows = init.arrows || [];
     this.selection = init.selection;
 }
}

interface Storable {
    boxes?: any[];
    arrows?: Arrow[];
    selection?: any;
}

interface Box {
 id: string;
 caption?: string;
}

interface Arrow {
    id: string;
    to?: Box;
    from?: Box;
}

const serializeState = createTransformer<Store, Store>(store => {
 return new Store({
     boxes: store.boxes.map(serializeBox),
     arrows: store.arrows.map(serializeArrow),
     selection: store.selection ? store.selection.id : null
 });
});

// copy using Object.assign (as this is just a simple JS object anyway)
const serializeBox = createTransformer<Box, Box>(box => Object.assign({}, box));

const serializeArrow = createTransformer<Arrow, Arrow>(arrow => {
 // or can copy manually...
 console.log("serializeArrow");  // this is only called 3 times!
 return {
     id: arrow.id,
     to: arrow.to,
     from: arrow.from
 };
});

const store = new Store();
const states: Storable[] = [];

autorun(() => {
 // this could be used to create an undo buffer, or whatever
 // probably wouldn't want infinite growth ... :) 
 states.push(serializeState(store));
});

const b1 = { id: "b1", caption: "Box 1" };
const b2 = { id: "b2", caption: "Box 2" };
const b3 = { id: "b3", caption: "Box 3" };
store.boxes.push(b1);
store.boxes.push(b2);
store.boxes.push(b3);

store.arrows.push({ id: "a1", from: b1, to: b2 });
store.arrows.push({ id: "a2", from: b1, to: b3 });
store.arrows.push({ id: "a3", from: b2, to: b3 });
b1.caption = "Box 1 - Edited";

// Should be 8
console.log(states.length);

b1.caption = "Box 1 - Final";

// Should be 9
console.log(states.length);

To make that work:


npm install --S mobx reflect-metadata
npm install --D @types/core-js

Sweet that MobX includes a TypeScript declarations file. :)

The things of interest here is that MobX assists in maintaining a stack of the object graph’s state, something that could be used for example in an undo buffer or comprehensive log system.

In this example, that’s done by using the MobX autorun functionality. When any of the dependencies of autorun changes, the function executes. In the example above, it makes a clone of the current store, using the createTransformer function, which turns a function into a reactive and memoizing function. Through memoization, it only transforms portions of the objects that have changed, not everything, every time. That doesn’t mean that you won’t want to limit the growth of the states, but you shouldn’t worry that a large complex object structure is being built with every change.

As TypeScript doesn’t support the object spread operator (which is convenient for making a clone of an object), I’ve used Object.assign instead (which may require a polyfill depending on the environment in which you use this code).

 

 

IHTMLDocument5 and IHTMLDocument6 in C#

Unexpectedly, I found myself needing to use IHTMLDocument5/6 last evening to fetch a few properties that aren’t directly exposed via any of the Web Browser options in classic .NET programming (like WinForms/WPF). I couldn’t find them anywhere, so I whipped up something simple/quick/dirty:

[Guid("3050f80c-98b5-11cf-bb82-00aa00bdce0b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)]
internal interface IHTMLDocument5
{
    void SetOnmousewheel(object p);
    object GetOnmousewheel();
    object docType { get; }
    object implementation { get; }
    object createAttribute([In] string attrName);
    object createComment([In] string comment);
    void SetOnfocusin(object p);
    object GetOnfocusin();
    void SetOnfocusout(object p);
    object GetOnfocusout();
    void SetOnactivate(object p);
    object GetOnactivate();
    void SetOndeactivate(object p);
    object GetOndeactivate();
    void SetOnbeforeactivate(object p);
    object GetOnbeforeactivate();
    void SetOnbeforedeactivate(object p);
    object GetOnbeforedeactivate();
    string compatMode { get; }
}


[Guid("30510417-98b5-11cf-bb82-00aa00bdce0b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)]
internal interface IHTMLDocument6
{
    object compatible { get; }
    object documentMode { get; }
    void SetOnStorage([In] object p);
    object GetOnStorage();
    void SetOnStorageCommit([In] object p);
    object GetOnStorageCommit();
    object getElementById([In] string id);
    void updateSettings();
}

As you can see, I didn’t spend a lot of time with the details, but it was enough to make progress (in particular I wanted compatMode and documentMode).

Animating an element’s visibility using AngularJS

There was a question on StackOverflow about animating an element and I wanted to give it a shot, so here goes:

http://jsfiddle.net/wiredprairie/5tFCZ/1/

image

 

Imagine nearly the simplest Angular JS application possible:

<div ng-app="App">
    <div ng-init="checked=true">
        <div>
            <label>
                <input type="checkbox" ng-model="checked" />Is Visible...</label>
        </div>
        <div class="sample" ng-class="{ hidden: !checked }">Visible...</div>
    </div>
</div>

There is only a single property called checked as part of the data model. There’s a checkbox that when unchecked, will cause the text “Visible” to be hidden.

I’m going to use jQuery as the simple animation engine, but you could use what ever you’d like. The latest versions of jQuery, angular, and angular-animate are needed:

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="http://code.angularjs.org/1.2.10/angular.min.js"></script>
<script src="http://code.angularjs.org/1.2.10/angular-animate.min.js"></script>

Using the ng-class directive (reference), a CSS class named hidden is added when the checkbox is not checked.

The application module and animation API are defined:

angular.module('App', ['ngAnimate']).animation('.sample', function () {
    return {
        addClass: function (element, className, done) {
            if (className === 'hidden') {
                jQuery(element)
                    .css({
                    opacity: 1
                })
                    .animate({
                    opacity: 0
                }, 500, done);
            } else {
                done();
            }
        },
        removeClass: function (element, className, done) {
            if (className === 'hidden') {
                jQuery(element)
                    .css({
                    opacity: 0
                })
                    .animate({
                    opacity: 1
                }, 500, done);
            } else {
                done();
            }
        }
    }
});

 

The only element animated on the page is using a CSS class name of sample. Whenever Angular adds or removes a CSS class from a matching HTML element, the corresponding code is executed. As it’s possible for multiple class names to be passed to the functions, per the guidelines, I’ve made sure that the code only executes when appropriate by filtering on the class name of hidden. As it’s toggling the state, the first action taken is to fully make opaque or transparent, then animate to zero or one depending on whether the class is being added or removed.

And that’s it! Of course, the code could have been more sophisticated, but it was all I needed.

By the way, there’s no need for a CSS class named hidden that has any CSS properties (it can be undefined completely). The animation code handles the visibility properly.

How to list all dependents of a Node package

You can use the web npm web site as it lists the dependents for any given package.

Like coffee-script for example:

http://npmjs.org/browse/depended/coffee-script

Or, you could get JSON results for the same query (using curl) (just substitute the name of the package with "sql" in the example:

> curl -g 'http://registry.npmjs.org/-/_view/dependedUpon?group_level=2&startkey=["sql"]&endkey=["sql","ZZZZZZZZZZZZZ"]&skip=0&limit=1000'

Results:

{"rows":[
{"key":["sql","anydb-sql"],"value":1},
{"key":["sql","dbal"],"value":1},
{"key":["sql","ectypes-downstairs"],"value":1},
{"key":["sql","fixr"],"value":1},
{"key":["sql","fixr-compiled"],"value":1},
{"key":["sql","forerunner-postgres-store"],"value":1}
{"key":["sql","pg-dal"],"value":1},
{"key":["sql","relational"],"value":1},
{"key":["sql","sequelize"],"value":1},
{"key":["sql","sql-generate"],"value":1},
{"key":["sql","sqlbox"],"value":1},
{"key":["sql","triplie"],"value":1},
{"key":["sql","voltron-postgres-adapter"],"value":1},
{"key":["sql","worm"],"value":1}
]}

The second value in the key array is the name of the package dependent on the sql package.

This of course only will find other published packages, and doesn’t help find applications, etc. that are using a specific package.

Loading Models in NodeJS

I’d answered a question on StackOverflow about where to put “models” in a NodeJS project. I wanted to elaborate on the simple auto loader I use to load a folder full of models (and I use this pattern other places as well). Normally, I create a folder called models:

image

Inside the Models folder, I have a file called, models.js.

Inside another module (like app.js), I’ve got a line of code that looks like this:

var models = require('./models').initialize(app, services);

While the require (reference) by default looks for a file called index.js in the folder models, I’ve in this case added a simple package.json file with an override:

{
    "main": "./models.js"
}

The reason I do this is that in a tabbed source code editor, having several index.js files can be confusing to see. So, this allows me to name the file something that is more memorable and understandable at a glance.

Inside of the models.js class, I’ve written code to automatically load all of the models (and call an initialize function once for each module):

var initialize = function(app, services) {
    var models = {};
    var currentFile = path.basename(__filename); // just file name
    var modelFiles = fs.readdirSync(__dirname);
    // loop through all of the files in the current directory
    for(var i= 0, len = modelFiles.length; i < len; i++) {
        // ignore this file (via global NodeJS variable)
        if(modelFiles[i] === currentFile ||
            path.extname(modelFiles[i]).toLowerCase() !== '.js') {
            continue;  // skip the current file and anything without a "JS" extension
        }
        // require it
        var model = require(path.join(__dirname, modelFiles[i]));
        // call its intialize
        model.initialize(services, models);
    }
    exports.models = models;
    return models;
};

exports.initialize = initialize;

The logic is simple enough – grab all of the files in the current path, then loop through each, filtering the current file and any that don’t end with “js”. This logic could be adjusted of course to reflect other coding styles and requirements.

Finally, each module is loaded and then an initialize method is called (admittedly, I could make it more robust by checking for the existence of the initialize function before calling it (but in this case, I know each module should be initialized in a particular way).