我是 Ember 的新手,正在尝试为 Solr API 实现类似 Google 的搜索界面。即我希望结果在您键入时在页面上自动更新。
我的第一个想法是创建一个可重用的 TextSearch CollectionView,它有两个子视图 SearchInput 和 SearchResults。
输入 SearchInput 将触发一个事件,该事件将被 TextSearch CollectionView 捕获,这将更新 SearchResult 子元素。
我得到了生成的事件,但 TextSearch ContainerView 无法使用操作、函数或事件管理器拦截事件。但是,出于某种原因,我可以拦截 IndexController 中的事件,但我需要在可重用的 TextSearch CollectionView 中处理它(我认为)。
最后,我无法更新 SearchResults 中的视图(当我尝试在 IndexController 中处理事件时),并且 SearchResult 模型在页面加载时没有触发。
我在 Ember 很新,所以我确定我在这里做了一些愚蠢的事情。达到这一点还有很长的路要走。
任何建议将不胜感激!
粘贴箱:http : //jsbin.com/ezomOkO/3/edit
HTML:
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
{{view App.TextSearchView }}
</script>
<script type="text/x-handlebars" data-template-name="textSearch">
{{view App.SearchInputView }}
{{view App.SearchResultsView }}
</script>
<script type="text/x-handlebars" data-template-name="searchInput">
{{input type="text" value=query size="50"}}
</script>
<script type="text/x-handlebars" data-template-name="searchResults" >
<ul>
{{#each concept}}
<li>{{title}}</li>
{{else}}
Sorry, nobody is here.
{{/each}}
</ul>
Javascript:
App = Ember.Application.create();
App.ApplicationController = Ember.Controller.extend({
appName: 'Snomed Search'
});
App.Router.map(function() {
this.route("index", {path: "/"});
});
// INDEX
App.IndexRoute = Ember.Route.extend({
});
App.IndexController = Ember.Controller.extend({
});
//TEXT SEARCH
App.TextSearchView = Ember.View.extend({
actions:{
search: function(search) {
this.get('controllers.searchResults').set('model', App.TextSearch.find(search));
return false;
}
},
needs: "searchResults",
templateName: 'textSearch'
});
// SEARCH INPUT
App.SearchInputController = Ember.Controller.extend({
query: 'Family'
});
App.SearchInputView = Ember.View.extend({
templateName: 'searchInput',
keyUp: function(evt) {
this.get('controller').send('search', this.get('controller.query'));
}
});
// SEARCH RESULTS
App.SearchResultsController = Ember.Controller.extend({
model: function(){
return App.TextSearch.find('Family');
},
afterModel: function(posts, transitions){
alert('model');
},
isPublic: true
});
App.SearchResultsView = Ember.View.extend({
templateName: 'searchResults'
});
App.SearchResults = Ember.Object.extend({
total: 0,
start: 0,
concepts: Ember.A()
});
App.Concept = Ember.Object.extend({
id: null,
title: null,
active: null,
effectiveTime: null
});
App.TextSearch = Ember.Object.extend({});
App.TextSearch.reopenClass({
find: function(searchString){
return Ember.Deferred.promise(function(p) {
p.resolve($.getJSON("http://solr.sparklingideas.co.uk/solr/concept/select?q=title:" + searchString + "&wt=json&indent=true")
.then(function(solr) {
var returned = App.SearchResults.create();
returned.total = solr.response.numFound;
returned.start = solr.response.start;
solr.response.docs.forEach(function (doc) {
var concept = App.Concept.create();
concept.id = doc.id;
concept.title = doc.title;
concept.active = doc.active;
concept.effectiveTime= doc.effectiveTime;
returned.concepts.push(concept);
});
return returned;
}) //then
);//resolve
});//deferred promise
}//find
});//reopen
更新
非常感谢您的帮助,杰里米,这就是我需要的所有信息。杰出的。
以下是一些经验教训:
在使用结果之前,您必须等待 JSON 承诺解决,如下所示:
search: function(search) { var results = App.TextSearch.find(search); var _this = this; // results is a jquery promise, wait for it to resolve // Ember can't resolve it automatically results.then(function(results){ _this.get('controllers.searchResults').set('model', results); }); return false; }
我不知道视图、渲染和控制器之间的区别(它的文档并不全,但谷歌搜索会告诉你)。但是这些与“部分”助手有什么关系呢?没有把握。
通过添加 '&json.wrf=?' 在 Solr URL 的末尾,您可以避免由于 XSS 安全性而在浏览器中阻止调用。
我对如何从视图中引用模型的 ember 文档感到非常困惑。这是正确的方法(对于这个例子):
<script type="text/x-handlebars" data-template-name="searchResults" > Total : {{model.total}} <ul> {{#each model.concepts}} <li>{{title}}</li> {{else}} Sorry, nobody is here. {{/each}} </ul> </script>
我的事件没有被视图控制器捕获,因为通过在模板中使用 {{view}} 助手,没有控制器(!)。改用 {{render}} 助手。
对于未来的读者,只需对提议的解决方案中的评论进行一个小的更正:
App.SearchResultsController = Ember.Controller.extend({
// This controller could be removed.
// Ember will auto generate one for you.
});
实际上,删除此控制器会导致 Javascript 错误:
Assertion failed: <App.TextSearchController:ember242> needs controller:searchResults but it does not exist
因为 SearchInputController 的需求属性。不过,在最后一个示例中,我最终从输入控制器中删除了对 searchResults 的依赖。
我相信 Ember 现在需要将事件处理程序包装在 'actions: {}' 参数中,如下所示:
actions:{
search: function(search) {
var results = App.TextSearchController.find(search);
var _this = this;
// results is a jquery promise, wait for it to resolve
// Ember can't resolve it automatically
results.then(function(results){
_this.get('controllers.searchResults').set('model', results);
});
return false;
}
}
请注意:
JSBin 使用了几个月前的 EmbeJS RC6。上面对在 'action' 属性中包装事件处理程序的更改似乎是在 RC6 之后引入的。如果您使用的是最新版本的 Ember(如您所愿),那么您的(事件)代码将无法在 JSBin 中工作(使用默认的 Ember 库)。但是,如果您不使用操作包装器,那么您的代码将无法在您的浏览器中运行。嗯……见github.com/emberjs/ember.js/releases
因此,在下面的 JSBin 示例中,我从事件处理程序中删除了“action:”标签,因此应用程序将运行。
我还做了一些小的设计更改:
- 我将搜索事件处理程序从 InputController 移动到包含 TextSearchController,以便将 InputController 与 SearchResultsController 分离。
- 我还删除了页面加载时的初始搜索,因此用户从空白开始。
- 最后,我删除了 TextSearch 对象,并将 solr 集成移至 TextSearchController。
最终版本可以在这里找到:http: //jsbin.com/ezExeCI/1/
杰里米,非常感谢您的帮助。没有你我做不到。我一定会付清的。
非常感谢!