我很困惑-我以为我有模型绑定正常工作,但它只是作为一个带有伪造ajax请求的jsFiddle。我已经将模型绑定到视图,如果我重写 .fetch() 并伪造响应,一切正常(我可以更新模型和页面上的视图更新)。然而,当我 不要 复盖 .fetch() 并使用 urlRoot 等待并等待响应,我得到错误。

下面是调用后渲染模型的工作jsFiddle .fetch() 用虚假的回应,而不是改变:

http://jsfiddle.net/franklovecchio/FkNwG/182/

所以如果我在服务器端有一个API调用:

/thing/:id

与示例响应 /thing/1:

{"id":"1","latitude":"lat1","longitude":"lon1"} 

我评论一下 .fetch(), ,我得到控制台错误:

load js core functions core.js:2
init model timeout app.js:114
initializer callback for history, routes app.js:95
App.Layouts.MyLayout onShow app.js:41
App.Regions.MyRegion onShow app.js:25
App.Models.Thing init app.js:55
App.ItemViews.Thing init app.js:87
Uncaught TypeError: Object #<Object> has no method 'toJSON' backbone.marionette-0.8.1.min.js:9
Parsing App.Models.Thing.fetch() response: {"id":"1","latitude":"lat1","longitude":"lon1"} app.js:62
Thing: {"id":"1","latitude":"lat1","longitude":"lon1"} app.js:66
a Thing has changed, update ItemView! app.js:57

Uncaught TypeError: Cannot call method 'render' of undefined app.js:58

update model app.js:108

Uncaught TypeError: Object #<Object> has no method 'set' 

.fetch() 评论出来了:

window.App = { }
window.App.Regions = { } 
window.App.Layouts = { }
window.App.Models = { } 
window.App.ItemViews = { } 
window.App.Rendered = { } 
window.App.Data = { }

# ----------------------------------------------------------------
# App.Regions.MyRegion
# ----------------------------------------------------------------

class MyRegion extends Backbone.Marionette.Region
  el: '#myregion'   
  onShow: (view) ->
    console.log 'App.Regions.MyRegion onShow'

App.Regions.MyRegion = MyRegion

# ----------------------------------------------------------------
# App.Layouts.MyLayout
# ----------------------------------------------------------------

class MyLayout extends Backbone.Marionette.Layout
  template: '#template-mylayout'  
  regions:
    contentRegion: '#content'
    anotherRegion: '#another'
  onShow: (view) ->
    console.log 'App.Layouts.MyLayout onShow'

App.Layouts.MyLayout = MyLayout

# ----------------------------------------------------------------
# App.Models.Thing
# ----------------------------------------------------------------

class Thing extends Backbone.Model

  urlRoot: () ->
    '/thing'

  initialize: (item) ->
    console.log 'App.Models.Thing init'
    @bind 'change', ->
      console.log 'a Thing has changed, update ItemView!'
      @view.render()

  parse: (resp) ->
    console.log 'Parsing App.Models.Thing.fetch() response: ' + JSON.stringify resp
    @attributes.id = resp.id
    @attributes.latitude = resp.latitude
    @attributes.longitude = resp.longitude
    console.log 'Thing: ' + JSON.stringify @
    @

  # If I don't override, I get an error.
  ###fetch: () ->
    console.log 'override ajax for test - App.Models.Thing.fetch()'
    resp =
      id: 1
      latitude: 'lat1'
      longitude: 'lon1'
    console.log 'Faked Thing response: ' + JSON.stringify resp
    @parse resp###

App.Models.Thing = Thing

# ----------------------------------------------------------------
# App.ItemViews.Thing
# ----------------------------------------------------------------

class Thing extends Backbone.Marionette.ItemView
  template: '#template-thing'
  initialize: (options) ->
    console.log 'App.ItemViews.Thing init'
    # Bind
    @options.model.view = @

App.ItemViews.Thing = Thing

# ----------------------------------------------------------------
# App.MyApp ...the Marionette application
# ----------------------------------------------------------------

App.MyApp = new Backbone.Marionette.Application()

# ----------------------------------------------------------------
# App.MyApp before init
# ---------------------------------------------------------------- 

App.MyApp.addInitializer (data) ->
  console.log 'initializer callback for history, routes'

  App.Rendered.myRegion = new App.Regions.MyRegion
  App.Rendered.myLayout = new App.Layouts.MyLayout

  App.Rendered.myRegion.show App.Rendered.myLayout

  # GET thing
  App.Data.thing = new App.Models.Thing(id: 1)
    .fetch()

  App.Rendered.thingView = new App.ItemViews.Thing(model: App.Data.thing)
  App.Rendered.myLayout.contentRegion.show App.Rendered.thingView

# ----------------------------------------------------------------
# Test
# ----------------------------------------------------------------

App.updateModel = ->
  console.log 'update model'

  # Update the Thing with id = 1
  App.Data.thing.set
    latitude: 'somenewlat'

App.updateModelTimeout = ->
  console.log 'init model timeout'
  setTimeout 'App.updateModel()', 2000

App.updateModelTimeout()

$ ->
  data = { }
  App.MyApp.start data

​
有帮助吗?

解决方案

这里发生了很多奇怪和困惑的事情。不要害怕,一切还没有失去,混乱可以解决。

骨干的 fetch 应该返回一个 jqXHR, ,而不是模型本身。你的 fetch 实现错误地返回 @parse resp 而你的 parse 申报表 @ (这也是不正确的,有时两个错误确实是正确的)。结果是这:

App.Data.thing = new App.Models.Thing(id: 1).fetch()

给你一个有用的 App.Data.thing 当你使用你的 fetch 但它不会是正确的骨干 fetch.所以你的 fetch 坏了,你没有用 fetch 正确无误;然后你试着给 jqXHR 到您的视图作为模型和您的视图集 @viewjqXHR 而不是模型:

initialize: (options) ->
  #...
  @options.model.view = @

所以你最终得到了一个 view 物业在 jqXHR 但该模型没有 @view (因为 App.Data.thing 不是模型),并且您在模型的更改处理程序中收到"无法调用未定义的方法'渲染'"错误。

你应该这样做:

App.Data.thing = new App.Models.Thing(id: 1)
App.Data.thing.fetch()

现在开始你的 parse:

parse: (resp) ->
  console.log 'Parsing App.Models.Thing.fetch() response: ' + JSON.stringify resp
  @attributes.id = resp.id
  @attributes.latitude = resp.latitude
  @attributes.longitude = resp.longitude
  console.log 'Thing: ' + JSON.stringify @
  @

精细手册:

解析,解析 每当服务器返回模型的数据时,都会调用 取货/取货, ,而 储蓄.该函数通过原始 response 对象,并应返回属性哈希为 套装 在模型上。

所以 parse 只是应该将服务器的响应按摩成可以 set 在模型上。你的 parse 设置属性并返回 @.结果是你最终会做相当于 m.set(m).所以摆脱你的 parse 实现,你的是不正确的,你甚至不需要一个。

你的模型/视图连接是向后的:视图引用模型,模型不引用视图。你的模型里有这个:

initialize: (item) ->
  console.log 'App.Models.Thing init'
  @bind 'change', ->
    console.log 'a Thing has changed, update ItemView!'
    @view.render()

这在你看来:

initialize: (options) ->
  console.log 'App.ItemViews.Thing init'
  # Bind
  @options.model.view = @

当你创建模型时,你应该将模型传递给视图(你是这样的,这是可以的):

App.Rendered.thingView = new App.ItemViews.Thing(model: App.Data.thing)

然后视图应该绑定到模型:

initialize: (options) ->
    @model.on('change', @render)

你可以把 initialize 在您的模型中实现。

此外,您可以(也应该)直接在命名空间中声明类,不要这样做:

class Thing extends Backbone.Marionette.ItemView
  #...
App.ItemViews.Thing = Thing

这样做:

class App.ItemViews.Thing extends Backbone.Marionette.ItemView
  #...

此外,字符串/eval形式 setTimeout 是邪恶几乎不应该被使用。不要这样做:

setTimeout 'App.updateModel()', 2000

这样做:

setTimeout (-> App.updateModel()), 2000

可能会有更多,但希望这会让你开始并解决你眼前的问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top