0

私は混乱しています-モデルバインディングが正しく機能していると思いましたが、それは偽のajaxリクエストを伴うjsFiddleとしてのみでした。モデルをビューにバインドしました.fetch()。応答をオーバーライドして偽造すると、すべてが機能します(モデルを更新し、ページでビューを更新できます)。ただし、パラメータを上書きして使用せずに応答を待つと、エラーが発生します。.fetch()urlRoot

.fetch()これは、変更されたものではなく、偽の応答で呼び出した後にモデルがレンダリングされる、動作中のjsFiddleです。

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

​
4

1 に答える 1

5

ここでは、奇妙で混乱したことがたくさん起こっています。心配する必要はありません。まだすべてが失われたわけではなく、混乱を整理することができます。

Backboneは、モデル自体ではなく、fetchを返すことになっています。実装が間違って返され、あなたjqXHRが返されます(これも正しくなく、2つの間違いが正しい場合もあります)。その結果、次のようになります。fetch@parse respparse@

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

App.Data.thingを使用すると便利ですfetchが、バックボーンの では正しくありませんfetch。したがって、あなたfetchは壊れていて、fetch正しく使用していません。次に、 をモデルとしてビューに与えようとしjqXHR、ビューはモデルではなくに設定@viewします。jqXHR

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

そのため、のviewプロパティになりますjqXHRが、モデルにはプロパティがなく@view(モデルではないためApp.Data.thing)、モデルの変更ハンドラーで「未定義のメソッド 'render' を呼び出すことができません」というエラーが発生します。

あなたはこれをしているはずです:

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 @
  @

細かいマニュアルから:

parseは、モデルのデータがサーバーによって返されるたびに、fetchおよびsaveで呼び出されます。この関数には生のオブジェクトが渡され、モデルに設定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
  #...

さらに、setTimeoutis Eval の文字列/評価形式は、ほとんど使用しないでください。これをしないでください:

setTimeout 'App.updateModel()', 2000

これを行う:

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

もっとあるかもしれませんが、うまくいけば、これがあなたを始めさせ、差し迫った問題を解決するでしょう.

于 2012-05-21T21:14:41.507 に答える