缺少骨干视图的模型,但我不明白为什么

时间:2012-06-27 14:11:19

标签: backbone.js

我有一个简单但令人困惑的问题。我有以下代码:

<div id="restaurant_locations"></div>

<script type="text/javascript">
  $(function() {
    window.router = new Lunchhub.Routers.RestaurantLocationsRouter({
      restaurantLocations: <%= @restaurant_locations.to_json.html_safe -%>
    });
    Backbone.history.start({pushState: true});
  });
</script>

会抛出此错误:

Uncaught TypeError: Cannot call method 'toJSON' of undefined

如果我取出{pushState: true}部分,只做Backbone.history.start()没有参数,它就可以正常工作。

错误旁边显示show_view.js: 19。以下是show_view.js的部分内容:

    ShowView.prototype.template = JST["backbone/templates/restaurant_locations/show"];

    ShowView.prototype.render = function() {
      $(this.el).html(this.template(this.model.toJSON())); // LINE 19
      Uncaught TypeError: Cannot call method 'toJSON' of undefined
      return this;
    }

所以我猜this.model未定义。这是show_view CoffeeScript:

Lunchhub.Views.RestaurantLocations ||= {}

class Lunchhub.Views.RestaurantLocations.ShowView extends Backbone.View
  template: JST["backbone/templates/restaurant_locations/show"]

  render: ->
    $(@el).html(@template(@model.toJSON() ))
    return this

如果我能使@model成为它需要的东西,我猜它可能会解决问题。但我不知道@model来自何处或其他任何地方。

我需要做什么?

编辑:我进一步了解。在下面的show函数中,id设置为“restaurant_locations”,当然没有@restaurantLocations的成员,其ID为restuarant_locationsid设置为restaurant_locations的事实具有一定的意义;我正在点击的网址是http://localhost:3000/restaurant_locations。但似乎它应该调用index函数,而不是show,如果这是我要去的URL。

class Lunchhub.Routers.RestaurantLocationsRouter extends Backbone.Router
  initialize: (options) ->
    @restaurantLocations = new Lunchhub.Collections.RestaurantLocationsCollection()
    @restaurantLocations.reset options.restaurantLocations

  routes:
    "new"      : "newRestaurantLocation"
    "index"    : "index"
    ":id/edit" : "edit"
    ":id"      : "show"
    ".*"        : "index"

  newRestaurantLocation: ->
    @view = new Lunchhub.Views.RestaurantLocations.NewView(collection: @restaurantLocations)
    $("#restaurant_locations").html(@view.render().el)

  index: ->
    @view = new Lunchhub.Views.RestaurantLocations.IndexView(restaurantLocations: @restaurantLocations)
    $("#restaurant_locations").html(@view.render().el)

  show: (id) ->
    restaurant_location = @restaurantLocations.get(id)

    @view = new Lunchhub.Views.RestaurantLocations.ShowView(model: restaurant_location)
    $("#restaurant_locations").html(@view.render().el)

  edit: (id) ->                   
    restaurant_location = @restaurantLocations.get(id)

    @view = new Lunchhub.Views.RestaurantLocations.EditView(model: restaurant_location)
    $("#restaurant_locations").html(@view.render().el)

1 个答案:

答案 0 :(得分:0)

  

id设置为"restaurant_locations",当然没有@restaurantLocations成员id "restuarant_locations"

听起来你有路由问题,所以让我们来看看你的路线:

routes:
  "new"      : "newRestaurantLocation"
  "index"    : "index"
  ":id/edit" : "edit"
  ":id"      : "show"
  ".*"       : "index"

我在那看到几个问题。首先,路由不是正则表达式,因此".*"/.*/不匹配(即任何字符序列),它实际上匹配任意数量的句点(即/^.*$/);您可以自己通过_routeToRegex运行它,看看'.*'会发生什么:

var namedParam    = /:\w+/g;
var splatParam    = /\*\w+/g;
var escapeRegExp  = /[-[\]{}()+?.,\\^$|#\s]/g;
//...
_routeToRegExp: function(route) {
  route = route.replace(escapeRegExp, '\\$&')
               .replace(namedParam, '([^\/]+)')
               .replace(splatParam, '(.*?)');
  return new RegExp('^' + route + '$');
},

下一个问题是":id"几乎可以匹配任何内容。 routeToRegexp":id"转换为/^([^/]+)$/;正则表达式匹配任何非空的非斜杠序列,特别是,它将匹配大多数其他路由匹配的内容。

因此,当您希望从'.*': 'index'点击/restaurant_locations时,您实际上正在点击':id': 'show',您很幸运'/new''/index'也被':id'匹配。请记住,(Java | Coffee)Script对象中元素的顺序是实现定义的,因此它们在源代码中出现的顺序确实无关紧要;许多JavaScript实现都会尊重源顺序,但从不依赖它。

由于路线顺序无关紧要,您必须将routes键视为一个简单的无序组,而您 - 人类 - 必须确保您的路线模式确实与不同的事物相匹配。如果确实需要重叠路由模式并且需要它们按特定顺序匹配,那么您可以使用路由器route中的initialize方法手动添加路由(作为路由模式或正则表达式)按要求的顺序。


执行摘要:修复您的路线,使其与不同的东西相匹配。