4

我正在尝试使用动态路由根据搜索字符串过滤数据。当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;
    });
}

当用户使用带有查询字符串的 url 访问应用程序时,#/search/red我只希望返回其中包含“红色”的卡片。

4

3 回答 3

7

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

具有计算属性:

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

与观察者:(更接近您的原始代码)

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

最好的方法是使用计算属性,但我不确定如何去做(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")
});
于 2013-09-04T10:25:36.387 回答
0

这是一种实现,其中控制器的模型内容属性在相应路由的setupController挂钩处明确分离。

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

球.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"}
]

应用程序.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

于 2013-09-04T18:55:13.710 回答
0

您是对的,问题是由于异步调用引起的。当您直接输入路线时,从您的 find 调用返回的对象是一个承诺,而不是一个实时列表。在处理它之前,您需要等待承诺解决。

像这样的东西应该工作:

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

请注意,根据您在上面调用时的加载方法(侧面加载与额外的 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

于 2013-09-06T19:47:15.587 回答