Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember.js filtering data from a dynamic route

I'm trying to filter data based on a search string using a dynamic route. When using the transitionToRoute function from a controller the model data from the route is returned to the viewproperly, however when navigating directly to the url or refreshing the page all the the forEach call is not being executed because the length of the data in the model is 0.

I have a feeling this is because the data is being loaded asynchronously, but I'm not sure how to delay the forEach loop and the rendering of the view until the find's promise is resolved and the forEach loop has completed.

Here is the model function of my router:

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

When a user hits the application with a url with a query string of #/search/red I want only the cards that have "red" in them returned.

like image 492
bittersweetryan Avatar asked Mar 22 '23 14:03

bittersweetryan


1 Answers

I just rediscovered this question and this is my try to give an answer. As i already mentioned in the comment, this are my basic ideas:

with Computed Properties:

  • Don't do the filtering in the model hook, just return the lists.
  • Set the query on the controller of your Route (named SearchController?)
  • Do the filtering in the controller as computed property

with Observers: (closer to your original code)

  • Don't do the filtering in the model hook, just return the lists.
  • Set the query on the controller of your Route (named SearchController?)
  • Take the logic to hide cards from your model hook and implement it as an observer on the Controller

The best approach would be to use computed properties, but i was not sure how to go about it (the Ember Team states that computed properties often lead to better code). Therefore here is a rough sketch of the code with the Observer approach. This should work out ok as a start:

Route:

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

Controller:

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")
});
like image 99
mavilein Avatar answered Mar 30 '23 00:03

mavilein