【问题标题】:Multiple backbone views referencing one collection引用一个集合的多个主干视图
【发布时间】:2012-08-03 15:24:03
【问题描述】:

我正在尝试创建我的第一个主干应用程序,但在理解我应该如何使用视图时遇到了一些困难。

我想要做的是有一个搜索输入,每次提交它都会从服务器获取一个集合。我想让一个视图控制搜索输入区域并监听那里发生的事件(在我的示例中单击按钮)和另一个视图,其中包含用于显示搜索结果的子视图。每次新的搜索只是将结果添加到搜索区域中。

单个结果将有其他方法(例如查找输入的日期或时间等)。

我有一个这样定义的模型和集合:

SearchResult = Backbone.model.extend({
    defaults: {
        title: null,
        text: null
    }
});

SearchResults = Backbone.Collection.extend({
    model: SearchResult,
    initialize: function(query){
        this.query = query;
        this.fetch();
    },
    url: function() {
        return '/search/' + this.query()
    }
});

在我看来,我有一个代表搜索输入的视图是:

var SearchView = Backbone.View.extend({
    el: $('#search'),
    events: {
        'click button': 'doSearch' 
    },
    doSearch: function() {
        console.log('starting new search');
        var resultSet = new SearchResults($('input[type=text]', this.el).val());
        var resultSetView = new ResultView(resultSet); 
    }
});

var searchView = new SearchView();

var ResultSetView = Backbone.View.extend({
    el: $('#search'),
    initialize: function(resultSet) {
        this.collection = resultSet;
        this.render();
    },
    render: function() {
        _(this.collection.models).each(function(result) {
            var resultView = new ResultView({model:result});
        }, this);
    }
});

var ResultView = Backbone.view.extend({
     tagName: 'div',
     model: SearchResult,
     initialize: function() {
         this.render();
     },
     render: function(){ 
         $(this.el).append(this.model.get(title) + '<br>' + this.model.get('text'));
     }
});

我的 html 看起来大致是这样的:

<body>
<div id="search">
    <input type="text">
    <button>submit</button>
</div>
<div id="results">

</div>

</body>

在我的代码中,它到达console.log('starting new search');,但没有从 ResultSetView 集合的初始化方法对服务器进行 ajax 调用。

我的设计是正确的还是有更好的方法来做到这一点。我认为因为这两个视图绑定到不同的 dom 元素,所以我不应该从另一个视图中实例化一个视图。任何建议表示赞赏,如果我需要更清楚地说明这一点,请告诉我,我会尽力改写问题。

【问题讨论】:

  • 你看到任何 JS 错误被抛出了吗?此外,ajax 调用将在您的 SearchResults Collection 的初始化时进行,因为这是您告诉它进行获取的地方。
  • 是的,它会登录到控制台,但不会发生 ajax 请求。也没有 js 错误。
  • 请注意,在实际实现中,ResultView 实例将被创建,但它们的render 结果不会添加到SearchView.$el
  • 代码是否到达SearchResults.initialize()?你能在this.fetch()前面加一个console.log吗?
  • 我在这里看到一个错字SearchResult = Backbone.model.extend({ ...

标签: backbone.js backbone-views


【解决方案1】:

一些问题(可能不是唯一的):

  • 您的 SearchView 未绑定到集合 reset 事件;正如所写,它将尝试立即渲染,而集合仍然是空的。
  • SearchView 实例化单个视图 ResultView,而它可能应该实例化复合视图 ResultSetView
  • 您正在向 SearchResults 集合的构造函数传递一个参数,但这不是正确的使用方法。关于这一点,请参阅documentation

【讨论】:

  • SearchView 可能不需要像 ResultSetView 那样监听重置事件,但可以很好地调用其他 cmets。
【解决方案2】:

您还没有告诉您的ResultSetView 收听集合中的任何事件。 “获取”是异步的。成功完成后,它会发送一个“reset”事件。您的视图需要侦听该事件,然后对该事件执行它需要执行的任何操作(例如渲染)。

【讨论】:

    【解决方案3】:

    修复示例代码中的所有错别字后,我有一个working jsFiddle

    单击按钮后,您会看到 AJAX 调用完成。当然响应是错误的,但这不是重点。

    所以我的结论是你的问题出在你代码的另一部分。

    【讨论】:

      【解决方案4】:

      在一些语法问题中,我在您的代码中看到的最可能的问题是竞争条件。在您的视图中,您假设 fetch 已经检索到数据并且您正在执行视图渲染方法。对于真正快速的操作,这可能是有效的,但它使您无法真正知道数据是否存在。处理这个问题的方法正如其他人所建议的那样:您需要监听集合的重置事件;但是,您还必须控制“何时”进行提取,因此最好仅在需要时进行提取 - 在搜索视图中调用 fetch。我对您的收藏和搜索视图进行了一些重组:

      var SearchResults = Backbone.Collection.extend({
          model: SearchResult,
          execSearch : function(query) {
              this.url = '/search/' + query;
              this.fetch();
          }
      });
      
      var SearchView = Backbone.View.extend({
          el: $('#search'),
          initialize : function() {
              this.collection = new SearchResults();
              //listen for the reset
              this.collection.on('reset',this.displayResults,this);
          },
          events: {
              'click button': 'doSearch' 
          },
          /**
          * Do search executes the search
          */
          doSearch: function() {
              console.log('starting new search');
              //Set the search params and do the fetch.
              //Since we're listening to the 'reset' event, 
              //displayResults will execute. 
              this.collection.execSearch($('input[type=text]', this.el).val());
          },
          /**
          * displayResults sets up the views. Since we know that the
          * data has been fetched, just pass the collection, and parse it
          */
          displayResults : function() {
              new ResultSetView({
                  collection : this.collection
              });
          }
      });
      

      请注意,我只创建了一次集合。这就是您所需要的一切,因为您使用相同的集合类来执行搜索。后续搜索只需要更改url即可。这比为每次搜索都实例化一个新集合更好的内存管理和更简洁。

      我没有进一步处理您的显示视图。但是,您可能会考虑坚持将散列传递给 Backbone 对象的约定。例如,在您的原始代码中,您将“resultSet”作为形式参数传递。但是,约定是将集合传递给表单中的视图: new View({collection: resultSet});我意识到这有点挑剔,但遵循约定可以提高代码的可读性。此外,您要确保以 Backbone 对象所期望的方式传递内容。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多