我正在尝试使用动态路由根据搜索字符串过滤数据。当使用来自控制器的transitionToRoute
函数时,路由中的模型数据会正确地返回到视图,但是当直接导航到URL或刷新页面时,由于数据的长度,所有的forEach调用都没有被执行在模型中是0.
我有一种感觉这是因为数据是异步加载的,但是我不知道如何延迟forEach循环和视图的呈现,直到find
的承诺得到解决并且forEach循环已经完成。
以下是我的路由器的model
功能:
model : function( params ){
var lists = App.List.find( ), //gets all the lists
query = params.query, //query string from url
re = new RegExp( query, 'i' );
this.set( 'query', query );
return lists.forEach( function( list ){
var cards = list.get( 'cards' ).forEach( function( card ){
//the view has a class bound to the hide property of each card
card.set( 'hide',
( query.length ) ? !( re.test( card.get( 'description' ) ) ) : false
);
} );
return list;
});
}
当用户使用查询字符串为#/search/red
的网址点击应用程序时,我只想要返回其中包含“红色”的卡片。
答案 0 :(得分:7)
我刚刚重新发现了这个问题,这是我试图回答的问题。正如我在评论中已经提到的,这是我的基本想法:
使用计算属性:
:(更接近原始代码)
最好的方法是使用计算属性,但我不知道如何去做(Ember团队声明计算属性通常会带来更好的代码)。因此,这是使用观察者方法的代码的草图。这应该可以作为一个开始:
<强>路线:强>
model : function( params ){
this.set( 'query', params.query );
return App.List.find(); //gets all the lists
},
setupController : function(controller, model) {
this._super(controller, model);
// setupController is a good location to setup your controller
controller.set("query", this.get("query"));
}
<强>控制器:强>
App.SearchController = Ember.ArrayController.extend({
query : '',
// this observer will fire:
// 1.: every time a list object is added or removed from the underlying array
// 2.: the query changes
modelAndQueryObserver : function(){
re = new RegExp( this.get("query"), 'i' );
return this.get("model").forEach( function( list ){
var cards = list.get( 'cards' ).forEach( function( card ){
//the view has a class bound to the hide property of each card
card.set( 'hide',
( query.length ) ? !( re.test( card.get( 'description' ) ) ) : false
);
} );
return list;
});
}.observes("model.@each", "query")
});
答案 1 :(得分:0)
以下是一个实现,其中控制器的 模型 和 内容 属性在处清楚地分开 setupController 相应路线的挂钩。
我在单独的文件中列出了不同颜色的球。
<强> balls.js 强>
[
{"id":1,"color":"darkred"},
{"id":2,"color":"lightred"},
{"id":3,"color":"darkgreen"},
{"id":4,"color":"lightgreen"},
{"id":5,"color":"darkblue"},
{"id":6,"color":"lightblue"}
]
<强> App.js 强>
App = Ember.Application.create();
App.Router.map(function() {
this.resource('balls',{path:"/balls/:color"});
});
App.BallsRoute = Ember.Route.extend({
model: function(params) {
return params;
},
serialize:function(model){return {color:model.color}},
setupController:function(cont,model){
var balls=Em.A();
if(!App.Balls)
App.Balls=$.getJSON("/start/js/balls.js");
App.Balls.then(function(json){
var re=new RegExp(model.color)
balls.setObjects(json);
var filtered =balls.filter(function(o,i){return re.test(o.color);});
cont.set('content',filtered);
});
}
});
App.ApplicationController=Em.Controller.extend({
searches:[{color:"red"},{color:"blue"},{color:"green"}]
});
App.BallsController=Em.ArrayController.extend({
});
<强> HTML 强>
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
<nav>
{{#each item in searches}}
{{#link-to "balls" item}} {{item.color}} {{/link-to}}
{{/each}}
</nav>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="balls">
<ul>
{{#each controller}}
<li>{{color}}</li>
{{/each}}
</ul>
</script>
我没有使用Ember数据,因为我对此不满意。
请检查此 Bin
答案 2 :(得分:0)
由于异步调用问题,你是对的。当您直接输入路径时,从查找调用返回的对象是承诺,而不是实时列表。在处理之前,您需要等待承诺解决。
这样的事情应该有效:
model : function( params ){
var lists = App.List.find( ), //gets all the lists
query = params.query, //query string from url
re = new RegExp( query, 'i' );
this.set( 'query', query );
// 'lists' is a promise, once it has resolved we can deal with it
lists.then(function(realLists){ // realLists is a real collection of models
realLists.forEach(function(list){
list.get('cards').forEach( function( card ){
//the view has a class bound to the hide property of each card
card.set( 'hide',
( query.length ) ? !( re.test( card.get( 'description' ) ) ) : false
);
});
});
});
// return the 'lists 'promise immediately
// maybe before the 'lists.then' function above has run
// Ember will resolve the promise for you and set up the controller correctly
return lists;
}
请注意,根据您在上面调用list.get('cards')
时的加载方式(侧面加载与其他http调用),您实际上可能会获得一个承诺而不是一组卡片。如果是这种情况,您可以使用相同的技术。
cards = list.get('cards');
cards.then(function(realCards){
realCards.forEach(...);
});
另外值得注意的是,在最新版本的Ember Data中,查找方法已发生变化。而不是App.List.find( )
你做this.store.find('list')
。 (过渡指南有关于突破性变化的更多信息。https://github.com/emberjs/data/blob/master/TRANSITION.md)