【问题标题】:Render a remote collection onto the page with Backbone.js使用 Backbone.js 将远程集合渲染到页面上
【发布时间】:2014-06-13 07:36:51
【问题描述】:

我正在使用 Backbone.js 和 Ruby on Rails 来呈现一组帖子,但屏幕上没有呈现任何内容。

应用文件

#= require_self
#= require_tree ./templates
#= require_tree ./models
#= require_tree ./views
#= require_tree ./routers

window.IntroProject =
  Models: {}
  Collections: {}
  Routers: {}
  Views: {}

  init: ->
    window.router = new IntroProject.Routers.HomepageRouter({})
    Backbone.history.start()

$ ->
  IntroProject.init()

模型和集合

class IntroProject.Models.Post extends Backbone.Model
  paramRoot: 'post'

class IntroProject.Collections.PostsCollection extends Backbone.Collection
  model: IntroProject.Models.Post
  url: '/'

路由器

class IntroProject.Routers.HomepageRouter extends Backbone.Router

  initialize: (options) ->
    @posts = new IntroProject.Collections.PostsCollection()
    @posts.fetch()


  routes:
    '':'index'

  index: ->
    @view ||= new IntroProject.Views.Posts.IndexView(collection: @posts)
    @view.render()

查看

IntroProject.Views.Posts ||= {}

class IntroProject.Views.Posts.IndexView extends Backbone.View

  el: '#posts'

  template: _.template( $('#home-post-template').html() ) if $("#home-post-template").length

  render: ->
    @$el.append( @template() )
    @
    # _.each(@collection, (post) =>
    #   postHtml = $(@template(post))
    #   @$el.append( postHtml )
    # )
    # @

模板

  <script type="text/template" id="home-post-template">
  <div class="row">
    <div class="small-12 columns">
      <h2 class="blog-post-title"><%= post.title %></h2>
      <small>
        <p class="blog-post-meta">Published on <%= post.created_at.strftime('%B %d, %Y') %>
          <% if (post.user.email) %>
          by <strong><%= post.user.email %></strong>
          <% end %>
        </p>
      </small>
      <hr>
      <div class="blog-post-body">
        <p><%= post.body.html_safe %></p>
      </div>
    </div>
  </div>
  </script>

我可以在加载页面时调用render(),因为我执行了console.log('hello')。我什至也做了console.log(@collection)。输出:

PostsCollection {models: Array[0], length: 0, _byId: Object, constructor: function, model: function…}
_byId: Object
_idAttr: "id"
length: 2
models: Array[2]
__proto__: ctor

所以他们的帖子在集合中。

当我执行@$el.append( @template() ) 时,它说post 未定义,所以我执行了@$el.append( @template(post: @collection.models)。但帖子未定义。

总的来说,我了解发生了什么,但它不起作用。我错过了一些重要的东西。这里是my github repo

更新:

答案建议的更改

路由器

class IntroProject.Routers.HomepageRouter extends Backbone.Router

  initialize: (options) ->
    @posts = new IntroProject.Collections.PostsCollection()
    @posts.fetch({ reset : true })

  routes:
    '':'index'

  index: ->
    @view ||= new IntroProject.Views.Posts.IndexView(collection: @posts)

查看

IntroProject.Views.Posts ||= {}

class IntroProject.Views.Posts.IndexView extends Backbone.View

  el: '#posts'

  template: _.template( $('#home-post-template').html() ) if $("#home-post-template").length

  initialize: ->
    @listenTo(@collection, 'reset', @render)

  render: ->
    _.each(@collection, (post) ->
      postHtml = @template( post )
      @$el.append( postHtml )
    , @)

模板,我从post.title 中删除了post

现在我通过控制台收到Uncaught ReferenceError: title is not defined

【问题讨论】:

标签: javascript ruby-on-rails ruby backbone.js coffeescript


【解决方案1】:

您的集合是异步获取的,这意味着当您在视图上调用渲染时,数据还没有出现。你可以在你的console.log(@collection) 中看到:它的length 是0。

您的视图需要监听它的集合并在它从服务器更改/返回时重新渲染。您可以将此函数添加到您的视图类中(对 CoffeeScript 不太熟悉,因此编写了 JS):

initialize : function(){
  this.listenTo(this.collection, 'reset', this.render);    
}

但由于在 fetch 调用返回时未明确触发 reset 事件,请将其更改为此(在路由器的设置中):

@posts.fetch({ reset : true });

另外,你的视图的 render 函数对我来说看起来不正确,我会写这个

render : function(){
  _.each(this.collection, function(model){
    var html = this.template( model.toJSON() );
    this.$el.append( html );
  }, this);
}

这也意味着您需要替换模板中对 post 的引用:

  • 替换`
  • &lt;%= title %&gt;

【讨论】:

  • 我已经实现了您的更改,但我无法使其工作。我已更新问题以反映更改。我已经在这里待了一个星期了,所以任何帮助都会很棒。
【解决方案2】:

在一些帮助下,我自己找到了答案。这是固定代码的样子。如果没有进行任何更改,则省略

路由器

class IntroProject.Routers.HomepageRouter extends Backbone.Router

  initialize: (options) ->
    @posts ||= new IntroProject.Collections.PostsCollection()

  routes:
    '':'index'

  index: ->
    @view ||= new IntroProject.Views.Posts.IndexView(collection: @posts)
    @posts.fetch()

查看

IntroProject.Views.Posts ||= {}

class IntroProject.Views.Posts.IndexView extends Backbone.View

  el: 'body'

  template: _.template( $('#home-post-template').html() ) if $('#home-post-template').length

  initialize: ->
    @collection.bind "reset", ->
      @render()
    , @

  render: ->
    @collection.each (post) =>
      $('#posts').append( @template(post.attributes) )
    @

模板

 <script type="text/template" id="home-post-template">
  <div class="row">
    <div class="small-12 columns">
      <h2 class="blog-post-title"><%= post.title %></h2>
      <small>
        <p class="blog-post-meta">Published on <%= post.created_at %>
          <% if (post.user.email) %>
          by <strong><%= post.user.email %></strong>
          <% end %>
        </p>
      </small>
      <hr>
      <div class="blog-post-body">
        <p><%= post.body %></p>
      </div>
    </div>
  </div>
  </script>

问题在于 fetch 和 render 调用。当路由器初始化时,我正在获取集合。集合不会保留在视图中。当我在视图上调用 render 时,没有任何东西可以渲染。

在解决方案中,我现在在视图初始化后拥有fetch()。一旦视图被初始化,一旦fetch() 成功,视图就会呈现,留下一个reset 事件被调用。我选择将el 设置为body,因为我有需要将el 设置为body 的事件。事件在el 中查找何时触发。

【讨论】:

    猜你喜欢
    • 2011-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    • 2012-07-25
    • 2016-05-19
    相关资源
    最近更新 更多