Ember.js过滤来自动态路由的数据

Ember.js filtering data from a dynamic route

本文关键字:路由 数据 动态 js 过滤 Ember      更新时间:2023-09-26

我正在尝试使用动态路由根据搜索字符串筛选数据。当使用控制器的transitionToRoute函数时,路由中的模型数据会正确返回到视图,但是,当直接导航到url或刷新页面时,由于模型中数据的长度为0,因此不会执行所有forEach调用。

我有一种感觉,这是因为数据是异步加载的,但我不知道如何延迟forEach循环和视图的渲染,直到find的promise得到解决,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点击应用程序时,我只希望返回其中包含"红色"的卡片。

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

具有计算属性:

  • 不要在模型挂钩中进行过滤,只需返回列表即可
  • 在路由的控制器上设置查询(名为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("model.@each", "query")
});

这里有一个实现,其中控制器的模型内容属性在相应路由的setupController//strong>挂钩处明显分离。

我在一个单独的文件中列出了不同颜色的球。

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数据,因为我对它不舒服。

请检查此纸盒

您对异步调用引起的问题是正确的。当您直接输入路由时,从find调用返回的对象是promise,而不是live列表。你需要等待承诺解决后再处理它。

像这样的东西应该起作用:

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调用),您实际上可能会得到一个promise,而不是一组卡片。如果是这样的话,你可以使用同样的技术。

cards = list.get('cards');
cards.then(function(realCards){
  realCards.forEach(...);
});

同样值得注意的是,在最新版本的Ember Data中,查找方法发生了变化。你应该做this.store.find('list')而不是App.List.find( )。(过渡指南提供了更多关于突破性变化的信息。https://github.com/emberjs/data/blob/master/TRANSITION.md)