Ember.js从动态路线过滤数据

时间:2013-08-29 18:02:24

标签: javascript ember.js

我正在尝试使用动态路由根据搜索字符串过滤数据。当使用来自控制器的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的网址点击应用程序时,我只想要返回其中包含“红色”的卡片。

3 个答案:

答案 0 :(得分:7)

我刚刚重新发现了这个问题,这是我试图回答的问题。正如我在评论中已经提到的,这是我的基本想法:

使用计算属性

  • 不要在模型钩子中进行过滤,只需返回列表。
  • 在Route的控制器上设置查询(名为SearchController?)
  • 将控制器中的过滤作为计算属性进行
观察员

(更接近原始代码)

  • 不要在模型钩子中进行过滤,只需返回列表。
  • 在Route的控制器上设置查询(名为SearchController?)
  • 采用逻辑从模型钩子中隐藏卡片并在Controller上以观察者的身份实现它

最好的方法是使用计算属性,但我不知道如何去做(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