Super simple SPA sample

This is going to be a really super simple sample showing you how to set up a single page application (SPA) using PathJs, KnockoutJs and HeadJs.

The code for this can be found in this Gist on GitHub.

Lets start with the HTML document index.html:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Super simple SPA template</title>
    </head>
    <body>
        <!-- Just some fake menu -->
        <a href="#/hello/sire">Hello</a>
        <a href="#/bye/sire">Bye</a>
    </body>
</html>

Ok, so have a quick look at the URLs in the super simple (poor) menu. It uses "hashbang" URLs, and with the help of PathJs this will let us invoke JavaScript functions without reloading the page or doing any new HTTPRequests.

Now, you probably are asking yourself:

"So, where’s the content coming from and where is it being shown?"

Excellent question! The content will be shown in a HTML element of your choice. In this simple demo, I’ve chosen this:

<div id="bindingContext"></div>

So whenever a registered route is being visited, the following will take place:

  1. The module matching the path will be used to create a view model
  2. The module name is used to identify a certain HTML-template to bind the view model to.
  3. The template is loaded into the bindingContext and then the view model is bound against the bindingContext using KnockoutJS.

Lets have a look at the module, defined in app.modules.js:

(function () {
    var module = app.modules.Hello = {
        route: 'hello/:msg',
        vm: function (req) {
            this.message = ko.observable(req.args['msg']);
        }
    };
})();

The route is what build the URL, which in this case will match index.html#/hello/world I’m using the functionality of PathJs to pass URL arguments via :paramname. The vm is the view model which will be instanciated using the new keyword. It just defines a simple Knockout observable for holding the message. In this case, we actually don’t need the observable since it’s populated before the binding.

Now, we need a template. For keeping it simple I’ve inlined them in index.html but you could easily load them e.g via AJAX, and you should then make use of content caching of the output. The template is really simple and looks like this:

<script id="hello.tmpl" type="text/html">
    <p>Hello
    <span data-bind="text: message"></span>!</p>
</script>

If you were paying attention you noticed we had two routes. One for Hello and one for Bye. We could make the template (view) and the view model more advanced, but lets just duplicate it for now. Introduce one more module and one more template.

(function () {
    var module = app.modules.Bye = {
        route: 'bye/:msg',
        vm: function (req) {
            this.message = ko.observable(req.args['msg']);
        }
    };
})();

<script id="bye.tmpl" type="text/html">
    <p>Bye
    <span data-bind="text: message"></span>!</p>
</script>

Are we good to go? Not yet, we need to load some JavaScript and initialize the app. I’m using a simple script loader (notice the them of SIMPLE) called HeadJs.

<script type="text/javascript" src="js/head.js"></script>
<script type="text/javascript">
    head
        .js('js/knockout.js')
        .js('js/path.js')
        .js('js/app.js', 'js/app.modules.js');

    head.ready(function () {
        app.init(document.getElementById('bindingContext'));
    });            
</script>

Just pass in the reference to the DOM-node that should act as the bindingContext and we are good to go!.

But, where is the missing pieces. The glue, the magic?

Well, again, this is a quite simple sample so it’s not that much code. Lets have a look at app.js.

(function (exports) {
    var app = exports.app = {
        bindingContext: { },
        modules: { },
        router: { },
        init: function (bindingCtxNode) { }
    };
})(window)

Ok, I confess, I simplified it and did just show you the "outlining". Lets fill in the missing pieces. Lets start with the bindingContext. It’s responsible for binding the view model to the view, so it’s actually also taking care of loading the template.

bindingContext: {
    domnode: null,
    model: null, //will hold the current view model instance
    loadTemplate: function (templateName) {
        return document.getElementById(templateName).innerHTML;
    },
    bind: function (templateName, vm) {
        this.domnode.innerHTML = this.loadTemplate(templateName);
        ko.applyBindings(vm, this.domnode);
        this.model = vm;
    },
    clear: function () {
        if(this.domnode !== null) this.domnode.innerHTML = null;
        this.model = null;
    }
}

Not so bad. A domnode to hold a reference (will be set in app.init later) to the div we defined above. The model is actually something you could rip out but could be nice if you want to play around with it using the console. loadtemplate just loads the <script>template</script> defined above and bind creates the view model instance and glues together the view template and Knockout.

Lets continue with the router.

router: {            
    registerModule: function (moduleName, module) {
        if (!module.route) module.route = moduleName.toLowerCase();
        if (!module.templateName) module.templateName = moduleName.toLowerCase() + '.tmpl';

        Path.map('#/' + module.route).to(function () {
            app.bindingContext.bind(module.templateName, new module.vm({args: this.params}));
        });
    },
    start: function () {
        Path.listen();
    }
},

It makes use of PathJs to map routes to certain modules. It also ensures that each module has a route and a templateName which has a really simple convention based on the moduleName. start is just something required by PathJs, otherwise it will not intercept the routes.

The missing piece is the init function.

init: function (bindingCtxNode) {
    this.bindingContext.domnode = bindingCtxNode;

    for(var moduleName in app.modules) {
        this.router.registerModule(moduleName, app.modules[moduleName]);
    }

    this.router.start();
}

It just goes through all the modules and registers them with the router. That’s it. You now have a foundation that you can start toying around with and extend.

//Daniel

NancyFx – Part 1 – Getting ready to use it

I have been aiming at trying out a micro web framework for a while and have been choosing between: JessicaFx and NancyFx; but I’ve never gotten the time, until now. My choice fell on Nancy, despite Tom Bell’s (creator of JessicaFx) article, in which he thinks that Nancy has taken steps away from being a micro web framework by not just extending the Asp.Net stack. I kind of like that Nancy offers other hosting capabilities and that they strive to not being dependent on the Asp.Net web stack, but who knows, in the end I might use JessicaFX instead. Don’t you just love OSS? Instead of a complex solution from Microsoft, targeting a multitude of scenarios, you get multitude of OSS projects solving a smaller problem domain for one of these scenarios.

This is not an ending story

This is part 1 of me exploring Nancy, and in this part I will only describe my way of getting good to go, to start working with Nancy.

Not a Ruby guy….yet

I also never have gotten the time to look at Ruby. And not being a Ruby guy at all, I thought “Hey, why not use Rake to build Nancy and that way start to get a little bit closer to Ruby by at least installing it and installing some gems.” I know that I could have settled with downloading the binaries or even simpler using NuGet but as I’m looking at using Rake myself, why not download the source of NancyFx and use Rake and Albacore to build it.

Get your hands on Ruby

Google it and you’ll find: http://www.ruby-lang.org/en/downloads/. Well there, and since I’m a Windows guy, I used the recommended way of heading over to: http://rubyinstaller.org/downloads/ and at the time of this writing the latest version was: Ruby 1.9.2-p180.

IronRuby

Nice to know for .Net people needing to extend their every day static language writing with some dynamic Ruby: http://www.ironruby.net/.

Disclaimer

Just so that you know. I haven’t investigated any best practices whatsoever in the context of installing Ruby and Gems.

Install…

During the installation I explicitly selected the two checkboxes to add it to the Path environment variable and to associate it with Ruby files.

After the installation was finnished I just fired up the command prompt and typed:

gem install rake
gem install albacore

Now I see where NuGet has been ripped from has gotten the inspiration from.

Get your hands on Nancy

Just head over to their GitHub page via http://nancyfx.org. Download the source and unzip it locally. After that just fire up the command window and navigate to the path where the “rakefile.rb” is located and type:

rake

That’s it. You now have yourself a set of compiled assemblies located under build\binaries, all tested and compiled on your machine. That’s it for this part. Next time, will actually open up our favourite choice of IDE, Visual Studio 2010???

//Daniel