我正在尝试创建我的第一个骨干应用程序,并且我很难理解我是如何使用视图的。
我要做的是拥有一个搜索输入,每次提交时都会从服务器获取一个集合。我希望有一个视图控制搜索输入区域并监听那里发生的事件(在我的示例中单击按钮)和另一个带子视图的视图用于显示搜索结果。每次新搜索只是将结果添加到搜索区域中。
单个结果将有其他方法(例如查找输入的日期或时间等)。
我有一个像这样定义的模型和集合:
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元素我不应该从另一个视图中实例化一个视图。任何建议都表示赞赏,如果我需要说清楚,请告诉我,我会尽力重新提出这个问题。
答案 0 :(得分:2)
一些问题(可能不是唯一的问题):
答案 1 :(得分:0)
您尚未告知ResultSetView
收听该集合上的任何活动。 “fetch”是异步的。成功完成后,它将发送“重置”事件。您的视图需要侦听该事件,然后对该事件执行任何需要执行的操作(如渲染)。
答案 2 :(得分:0)
答案 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对象所期望的方式传递内容。