I'm having a look at the Hot Towel template, and trying to get it to work in TypeScript, I've encountered a problem converting the shell viewmodel. I'm trying to translate this into TS, and it makes more sense to me that it should be a class, rather than simply exporting functions as shown here. I looked at this approach but, paying attention to the comments here, decided against following it.
After a bit of digging I found this thread, which suggested it should be as simple as overriding router.getActivatableInstance
, but I can't seem to get far enough for that function ever to be called.
Here's my main.ts
(also wrapped up in a class):
/// <reference path="dts/toastr.d.ts" />
/// <reference path="dts/durandal.d.ts" />
/// <reference path="dts/require.d.ts" />
import _app = module('durandal/app');
import _system = module('durandal/system');
import _viewLocator = module('durandal/viewLocator');
import _router = module('durandal/plugins/router');
import _logger = module('services/logger');
export class HOPS {
public init(): void {
_logger.log('init', this, 'HOPS', false);
_system.debug(true);
this._startApp();
}
private _startApp(): void {
_logger.log('_startApp', this, 'HOPS', false);
_app.start().then(() => {
toastr.options.positionClass = 'toast-bottom-right';
toastr.options.backgroundpositionClass = 'toast-bottom-right';
var defImpl = _router.getActivatableInstance; //default Implementation
_router.getActivatableInstance = function (routeInfo: _router.routeInfo, paramaters: any, module: any) {
var functionName = routeInfo.name.substring(0, 1).toUpperCase() + routeInfo.name.substring(1);
if (typeof module [functionName] == 'function') {
var instance = new module [functionName]();
instance.__moduleId__ = module.__moduleId__;
return instance;
}
else return defImpl(routeInfo, paramaters, module );
}
_router.handleInvalidRoute = (route: _router.routeInfo, paramaters: any) => {
_logger.logError('No Route Found', route, 'main', true);
}
_router.useConvention();
_viewLocator.useConvention();
_app.adaptToDevice();
_app.setRoot('viewmodels/shell', 'entrance');
});
}
}
var hops: HOPS = new HOPS();
hops.init();
(Playground showing JS here: http://bit.ly/WyNbhn)
... and here's my shell.ts
:
import _system = module('durandal/system');
import _router = module('durandal/plugins/router');
import _logger = module('services/logger');
export class Shell{
public router = _router;
public activate(): JQueryPromise {
_logger.log("activate", null, 'shell', false);
return this.boot();
}
public boot(): JQueryPromise {
_logger.log("boot", null, 'shell', false);
this.router.mapNav('home')
this.router.mapNav('details');
_logger.log('SciHops SPA Loaded!', null, _system.getModuleId(this), true);
return this.router.activate('home');
}
}
... which compiles to:
define(["require", "exports", 'durandal/system', 'durandal/plugins/router', 'services/logger'], function(require, exports, ___system__, ___router__, ___logger__) {
/// <reference path="../dts/_references.ts" />
var _system = ___system__;
var _router = ___router__;
var _logger = ___logger__;
var shell = (function () {
function shell() {
this.router = _router;
}
shell.prototype.activate = function () {
_logger.log("activate", null, 'shell', false);
return this.boot();
};
shell.prototype.boot = function () {
_logger.log("boot", null, 'shell', false);
this.router.mapNav('home');
this.router.mapNav('details');
_logger.log('SciHops SPA Loaded!', null, _system.getModuleId(this), true);
return this.router.activate('home');
};
return shell;
})();
exports.shell = shell;
})
With the class above, I get a binding error because router
is undefined. If I add export var router = _router
then this bug goes away but the activate method on my shell class is never called.
All of the above works well for subsequent viewmodels, but just falls over on the shell.
What am I doing wrong, and how can I get a TS class working as my shell Durandal viewmodel?