我有一个简单但令人困惑的问题。我有以下代码:
<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_locations
。 id
设置为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)
答案 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
方法手动添加路由(作为路由模式或正则表达式)按要求的顺序。
执行摘要:修复您的路线,使其与不同的东西相匹配。