How can I use a class for my view shell model in Durandal?

I am looking at the Hot Towel template and trying to get it to work in TypeScript, I am faced with the problem of converting the viewmodel shell. I am trying to translate this into TS, and for me it makes more sense that it should be a class, and not just export functions, as shown here . I looked at this approach , but paying attention to the comments here , following it.

After a little digging, I found this thread , which suggested that it should be as simple as redefining router.getActivatableInstance , but I can't seem to be far enough that this function ever gets called.

Here is my main.ts (also wrapped 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(); 

(A playground featuring JS here: http://bit.ly/WyNbhn )

... and here is 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 , this error will disappear, but the activation method in my shell class is never called.

All of the above works well for subsequent viewing modes, but just falls on the shell.

What am I doing wrong, and how can I get a TS class that works like my Durandal shell model?

+5
source share
2 answers

The problem is that your router does not allow your shell.ts module.

All other view modes go through the router.getActivatableInstance method and are created and bound to __moduleId__ . Except your shell.ts module.

This is a quick and dirty way to get your shell.ts module working.

Inside main.ts , your shell.ts module may be required:

 import _shell = module('shell'); 

Then, while inside main.ts , you can create an instance of the shell class and assign it moduleId.

 var shell = new _shell.Shell(); shell.__moduleId__ = _shell.__moduleId__; _app.setRoot(shell, 'entrance'); 

Not the most beautiful thing you've ever seen. But he does his job. This pretty much does the same thing as getActivatableInstance overrides your actions. Since your shell does not go through the router.js module, you need to do this manually.

+4
source

Another option is to export the class as a module for Duranal. note: this method also works for view modes.

A working example based on the nuget "Durandal Starter Kit":

  import router = require('plugins/router') import app = require('durandal/app') class Shell { router = router; public search() { //It really easy to show a message box. //You can add custom options too. Also, it returns a promise for the user response. app.showMessage('Search not yet implemented...'); } public activate() { router.map([ { route: '', title: 'Welcome', moduleId: 'viewmodels/welcome', nav: true }, { route: 'flickr', moduleId: 'viewmodels/flickr', nav: true }, ]).buildNavigationModel(); return router.activate(); } } // Magic happens here: export = Shell; 

Original code "js":

  define(['plugins/router', 'durandal/app'], function (router, app) { return { router: router, search: function() { //It really easy to show a message box. //You can add custom options too. Also, it returns a promise for the user response. app.showMessage('Search not yet implemented...'); }, activate: function () { router.map([ { route: '', title:'Welcome', moduleId: 'viewmodels/welcome', nav: true }, { route: 'flickr', moduleId: 'viewmodels/flickr', nav: true }, ]).buildNavigationModel(); return router.activate(); } }; }); 
+3
source

Source: https://habr.com/ru/post/945357/


All Articles