0

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

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

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

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

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 元素,所以我不应该从另一个视图中实例化一个视图。任何建议表示赞赏,如果我需要更清楚地说明这一点,请告诉我,我会尽力改写这个问题。

4

4 回答 4

2

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

  • 您的SearchView未绑定到集合重置事件;正如所写,它将尝试立即渲染,而集合仍然是空的。
  • SearchView在可能应该实例化复合视图ResultSetView时实例化单个视图ResultView
  • 您将参数传递给SearchResults集合的构造函数,但这不是使用它的正确方法。请参阅有关这一点的文档。
于 2012-08-03T15:39:27.250 回答
0

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

于 2012-08-03T15:38:43.927 回答
0

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

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

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

于 2012-08-03T15:50:53.600 回答
0

在一些语法问题中,我在您的代码中看到的最可能的问题是竞争条件。在您的视图中,您假设 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 对象所期望的方式传递内容。

于 2012-08-03T16:45:30.100 回答