2013-08-29 73 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