2013-08-29 35 views
4

我试图使用动态路由基于搜索字符串过滤数据。在控制器中使用transitionToRoute函数时,路由中的模型数据将返回到视图的正确位置,但是,直接导航到url或刷新页面时,所有forEach调用都未执行,因为模型中数据的长度为0.Ember.js过滤来自动态路由的数据

我有一种感觉,这是因为数据异步加载,但我不知道如何延迟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查询字符串的URL我想只有那些“红”在他们返回的卡的应用。

+0

是的,这绝对是因为异步调用。你可以创造你自己的承诺。但是这段代码看起来有点难看。我建议在控制器上设置搜索查询,该控制器包含列表。这个控制器然后可以用一个计算的属性过滤你的列表。您的方法非常重要,而Ember想要宣传声明式编程。 – mavilein

+0

@mavilein谢谢,我正在开始这条路,但我有问题将查询参数传递到控制器。我很乐意看到您的评论作为答案的例子(如果是其他内容,我可以投票) – bittersweetryan

+0

为什么不直接将参数传递给'find()'方法并让后端完成工作(除非你使用夹具数据当然)? – kroofy

回答

7

我刚刚重新发现了这个问题,这是我的尝试给出的答案。正如我在评论已经提到的,这是我的基本思路:

使用计算性能:

  • 不要做模型钩过滤,只返回列表。
  • 设定路线的控制器上的查询(名为SearchController?)
  • 执行过滤控制器作为计算财产

与观察员:(接近你原来的代码)

  • 不要在模型钩子中进行过滤,只返回列表。
  • 设置查询路线的控制器(名为SearchController?)
  • 取逻辑为模型钩子隐藏卡并执行它作为控制器

观察员最好的办法是使用计算的属性,但我不知道如何去做(Ember团队指出计算属性通常会导致更好的代码)。因此,这里是Observer方法的代码的粗略草图。这应该制定出好的作为开始:

路线:

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("[email protected]", "query") 
}); 
+0

你可能在这一行中忘了一个右括号:'re = new RegExp(this.get(“query”),'i');' – iguider

+0

你是对的。修复。谢谢 :-) – mavilein

0

这里是一个实施方案,其中模型内容控制器的属性在设置控制器明确分隔相应路由的钩子。

我有不同颜色的球在一个单独的文件列表。

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> 

我不使用灰烬数据,因为我不舒服。

请检查该 Bin

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; 
} 

请注意,根据您的加载方法(侧装VS额外的HTTP调用)当你在上面打电话list.get('cards'),你实际上可能得​​到一个承诺,而不是卡的集合的。如果是这种情况,你可以使用相同的技术。

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