2

I'm trying to convert a basic Backbone.js router declaration to TypeScript.

var AppRouter = Backbone.Router.extend({
    routes: {
        "*actions": "defaultRoute"
    },

    defaultRoute: function () {
        document.write("Default Route Invoked");
    }
});

var app_router = new AppRouter();

Backbone.history.start();

My converted code is the following which doesn't work:

class AppRouter extends Backbone.Router {
    routes = {
        "*actions": "defaultRoute"
    }

    defaultRoute() {
        document.write("Default Route Invoked");
    }
}

var app_router = new AppRouter();

Backbone.history.start();

I get no compile time or runtime errors but the code does not function. Why?

freejosh
  • 11,263
  • 4
  • 33
  • 47
orad
  • 15,272
  • 23
  • 77
  • 113

4 Answers4

2

I've had a look at Backbone.Router.extends and it isn't a basic prototype extension - so you can't just switch from Backbone.Router.extends to a TypeScript class extension.

I would change your TypeScript file to look more like your original JavaScript - you'll still get the benefit of intellisense and type checking - you just aren't using a class:

var AppRouter = Backbone.Router.extend({
    routes: {
        "*actions": "defaultRoute"
    },

    defaultRoute: function () {
        document.write("Default Route Invoked");
    }
});

var app_router = new AppRouter();

Backbone.history.start();
Fenton
  • 241,084
  • 71
  • 387
  • 401
  • Backbone [source](http://backbonejs.org/docs/backbone.html#section-193) shows that the extend method is the same for all backbone types. `Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;` where do you see difference in the router's prototype extension? – orad Jan 30 '13 at 19:40
  • 1
    I wasn't suggesting the Backbone ones are different to each other - they are different to the one generated by TypeScript when you use inheritance. You can use `var app_router: Backbone.Router = ...` but TypeScript will probably already type app_router without making it explicit. – Fenton Jan 30 '13 at 20:45
  • I expanded this question a little more in [this other Q/A](http://stackoverflow.com/questions/14632714/converting-backbone-structures-to-typescript). – orad Jan 31 '13 at 18:47
  • 1
    @orad I answered your question. [Take a look here](http://stackoverflow.com/questions/14632714/converting-backbone-structures-to-typescript/14657969#14657969) – Diullei Feb 02 '13 at 02:27
2

Add all initialized fields in the constructor and make a call to super at the end:

class AppRouter extends Backbone.Router {

    routes: any;
    constructor(options?: Backbone.RouterOptions) {

        this.routes = {
            "*actions": "defaultRoute"
        }

        super(options);
    }

    initialize() {
        // can put more init code here to run after constructor
    }

    defaultRoute() {
        document.write("Default Route Invoked");
    }
}

var app_router = new AppRouter();

Backbone.history.start();
orad
  • 15,272
  • 23
  • 77
  • 113
  • 4
    I get this error. A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties. – rolnn Jan 13 '15 at 03:56
2

As Steve Fenton mentioned it's because Typescripts extend does not work in the same way as underscore / backones extend method.

The main problem is that the router calls _bindRoutes() before your routes field has been set in the "sub class" in type scripts hierachy.

A call to Backbone.Router.apply(this, arguments) in the constructor of your ts class as described by orad, ensures that this call will be made after the routes field has been set.

A manual call to this function will do the trick as well.

and just a FYI: call delegateEvents(this.events) in the constructor of your view classes if you want the dom events from your element to get triggered

Tau Sand
  • 23
  • 3
0

The accepted answer doesn't seem to work with typescript 3.x . The super() method should be called before using this. Reordering code won't work because backbone is initializing routes within the super() method. Here is a version where the route configuration is directly passed to super().

class AppRouter extends Backbone.Router {

    constructor() {

        super({
            routes: {
                "*actions": "defaultRoute"
            }
        });
    }
}
Martins Balodis
  • 1,999
  • 1
  • 17
  • 18