2012-08-03 63 views
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');但没有Ajax调用MA从ResultSetView集合的初始化方法到服务器。

我在设计这个权利还是有更好的方法来做到这一点。我认为,因为这两个视图绑定到不同的DOM元素,我不应该从另一个视图中实例化一个视图。任何建议表示赞赏,如果我需要说明这个更清楚,请让我知道,我会尽我所能来重述这个问题。

+1

你是否看到任何JS错误被抛出? 此外,ajax调用将在您的'SearchResults''Collection'的初始化过程中进行,因为这是您告诉它执行抓取的位置。 – bvulaj 2012-08-03 15:28:58

+0

是的,它会登录到控制台,但不会发生ajax请求。也没有js错误。 – justinfay 2012-08-03 15:36:30

+0

请注意,在实际的实现中,'ResultView'实例将被创建,但它们的'render'结果将不会被添加到'SearchView。$ el'中。 – fguillen 2012-08-03 15:36:39

回答

2

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

  • 搜索查看未绑定到集合复位事件;正如书面文字,它会立即尝试渲染,而集合仍然是空的。
  • 搜索查看实例化单一视图ResultView当推测它应该实例化复合视图ResultSetView
  • 您正将一个参数传递给SearchResults集合的构造函数,但这不是正确的使用方法。关于这一点,请参阅documentation
+1

SearchView可能不需要像ResultSetView一样监听重置事件,但可以很好地调用其他注释。 – JayC 2012-08-03 15:42:51

0

您还没有告诉您的ResultSetView收听收藏上的任何事件。 “获取”是异步的。成功完成后,它将发送一个“重置”事件。您的视图需要监听该事件,然后执行该事件所需的任何操作(如渲染)。

0

在你的例子代码修复所有错别字后,我有一个working jsFiddle

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

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

0

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

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对象期望的方式传递事物。