У backbone.js возникли проблемы с fetch () в коллекции. - PullRequest
0 голосов
/ 09 декабря 2011

Предупреждение: код в Coffeescript. Я надеюсь, что все в порядке.

У меня есть модель, Song, коллекция Songs и представление SongsView. Вот оно:

SONG_TEMPLATE = '''
  <table>
  {{#if songs.length }}
    {{#each songs}}
        <tr><td>{{ this.name }}</td><td>{{ this.duration }}</td></tr>
    {{/each}}
  {{/if}}
  </table>
'''

$ ->
  class Song extends Backbone.Model
    parse: (response) ->
      console.log "model parsing #{response}"
    #

  class Songs extends Backbone.Collection
    initialize: ->
      @model = Song
      @url   = "/songs/data"

    parse: (response) ->
      console.log "collection parsing"
      console.log response

  # This works. The JSON here was grabbed right out of the XHR response I got from the server and pasted into my code.

  songs = new Songs(
    [
      {"name":"Stray Cat Strut","rating":4,"duration":3},
      {"name":"Chinatown","rating":2,"duration":4.2},
      {"name":"Sultans of Swing","rating":3,"duration":5.4},
      {"name":"Pride & Joy","rating":3,"duration":3}
    ]
    )

  # This fails. It should be exactly the same as the above code, and indeed, the collection parsing takes place.
  # However, the view renders nothing.

  # songs = new Songs
  # songs.fetch()

  class SongsView extends Backbone.View
    initialize: ->
      @model = Song
      @render()

    render: =>
      console.log "render"
      console.log @collection
      template = Handlebars.compile(SONG_TEMPLATE)
      @template = template(songs: @collection.toJSON())
      console.log "template: #{@template}"
      $('#song-list').html @template

  songView = new SongsView(collection: songs)

Проблема, с которой я столкнулся, заключается в том, что есть некоторая тонкая разница между инициализацией songs из строки JSON и разрешением магистрали заполнять ее, используя fetch(). Объект выглядит нормально в окне отладки скрипта, но не радости.

Итак, что здесь происходит, и я на правильном пути?

Спасибо

Ответы [ 2 ]

3 голосов
/ 09 декабря 2011

Fetch - это асинхронный метод, это означает, что когда вы отображаете представление, данные не были извлечены, но когда вы пишете его вручную, данные там есть.Общий способ сделать это - привязать триггер сброса, который вызывается fetch, к методу рендеринга.

class SongsView extends Backbone.View
  initialize: ->
    @model = Song
    @collection.bind("reset", @render)
  render: =>
    console.log "render"
    console.log @collection
    template = Handlebars.compile(SONG_TEMPLATE)
    @template = template(songs: @collection.toJSON())
    console.log "template: #{@template}"
    $('#song-list').html @template

Вероятно, вам следует поместить больше ваших songs.fetch ниже, где вы также создаете экземпляр своего представления.

0 голосов
/ 16 мая 2013

Как ответил Газлер, проблема в том, что fetch является асинхронным.Если вы хотите использовать решение Газлера, помните, что метод fetch коллекции больше не вызывает событие reset по умолчанию.Следовательно, вам нужно, чтобы коллекция явно вызывала событие reset:

my_collection.fetch({reset: true})

Еще одно решение этой проблемы - использование jQuery deferreds для отображения представления после получения результатов.Еще один, использующий deferreds для управления отображением представления при асинхронной выборке данных: http://davidsulc.com/blog/2013/04/01/using-jquery-promises-to-render-backbone-views-after-fetching-data/

и ожидание возврата нескольких асинхронных источников данных: http://davidsulc.com/blog/2013/04/02/rendering-a-view-after-multiple-async-functions-return-using-promises/

...