多个主干视图引用一个集合

时间:2012-08-03 15:24:03

标签: backbone.js backbone-views

我正在尝试创建我的第一个骨干应用程序,并且我很难理解我是如何使用视图的。

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

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

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

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集合的initialize方法调用服务器。

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

4 个答案:

答案 0 :(得分:2)

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

  • 您的 SearchView 未绑定到集合重置事件;正如所写,它会立即尝试渲染,而集合仍然是空的。
  • SearchView 实例化单个视图 ResultView ,大概是它应该实例化复合视图 ResultSetView
  • 您正在将参数传递给 SearchResults 集合的构造函数,但这不是使用它的正确方法。有关此问题,请参阅documentation

答案 1 :(得分:0)

您尚未告知ResultSetView收听该集合上的任何活动。 “fetch”是异步的。成功完成后,它将发送“重置”事件。您的视图需要侦听该事件,然后对该事件执行任何需要执行的操作(如渲染)。

答案 2 :(得分:0)

修复示例代码中的所有拼写错误后,我有一个working jsFiddle

您看到点击按钮后完成了AJAX调用。当然,回复是错误的,但这不是重点。

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

答案 3 :(得分:0)

在一些语法问题中,我在您的代码中看到的最可能的问题是竞争条件。在您的视图中,您假设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
        });
    }
});

请注意,我只创建了一次集合。这就是您需要的所有内容,因为您使用相同的集合类来执行搜索。后续搜索只需要更改网址。这是更好的内存管理,比为每次搜索实例化一个新集合更清晰。

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