Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js - Coffeescript extends

I'm making chaining selects with backbone.js by this article http://blog.shinetech.com/2011/07/25/cascading-select-boxes-with-backbone-js/, but got errors, when extending classes.

So, i have LocationsView class:

class Blog.Views.LocationsView extends Backbone.View
  events:
    "change": "changeSelected"

CountriesView class:

class Blog.Views.CountriesView extends Blog.Views.LocationsView
  setSelectedId: (countryId) ->

CitiesView class:

class Blog.Views.CitiesView extends Blog.Views.LocationsView
  setSelectedId: (cityId) ->

But when coffeescript code compiled to javascript my double extended classes looks like:

(function() {
  var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
    for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
    function ctor() { this.constructor = child; }
    ctor.prototype = parent.prototype;
cities_view.js:5 Uncaught TypeError: Cannot read property 'prototype' of undefined
    child.prototype = new ctor;
    child.__super__ = parent.prototype;
    return child;
  };
  Blog.Views.CitiesView = (function() {
    __extends(CitiesView, Blog.Views.LocationsView);
    function CitiesView() {
      CitiesView.__super__.constructor.apply(this, arguments);
    }
    CitiesView.prototype.setSelectedId = function(cityId) {};
    return CitiesView;
  })();
}).call(this);

And i got error:

Uncaught TypeError: Cannot read property 'prototype' of undefined    cities_view.js:5

So, where the problem is and how to fix it?

like image 344
BazZy Avatar asked Nov 02 '11 07:11

BazZy


2 Answers

Since you are using ROR, is it correct to say that you are using 3.1 with the asset pipeline? If you are not using 3.1, then this info might still be useful, depending on how you are doing things.

The asset pipeline in 3.1 will bring your js files in alphabetical order when the files are within the same folder.

Because of that, cities_view.js will be executed before locations_view.js. Then, when CitiesView tries to define itself, LocationsView doesn't exist yet. (But this confuses me a bit because shouldn't you be using .coffee files instead of .js files?)

You will have to muck with the order of the files in the asset pipeline (controllable via comments) in order to get the correct file executed... or change the names.

In other words, you can tell Sprockets (the thing in RoR which manages your asset pipeline) to require the other file first.

At the top of your cities_view.coffee file, you can add the following line:

##= require ./locations_view

Good luck

like image 71
Brian Genisio Avatar answered Sep 19 '22 17:09

Brian Genisio


As @brian Genisio says, Its the alphabetical ordering of file loading in ROR's asset pipeline that's the issue.

I've found it useful to put all models that inherit from others in a sub-directory. This way, ROR loads all files in the parent directory first, before loading files in the sub-directory. It also appears more logical to the reader.

e.g. vehicle.js and car.js (where car extends vehicle) in the same directory wouldn't work, as car.js is loaded and run before vehicle.js, and isn't able to inherit from it.

Putting car.js in a sub directory (e.g. vehicle_models/car.js) would then work.

like image 35
Tom Wilshere Avatar answered Sep 22 '22 17:09

Tom Wilshere