Filter data client side


#1

I am getting my feet wet with Ember. I have followed Zoltan Debre’s excellent tutorial on www.yoember.com. It all looks very promising and I quickly got the hang of the basics. (For those who don’t know the tutorial, it lets you create a library system with books and authors.)

I decided to give myself a little challenge and created a page that lists all the books. I was pleasantly surprised to see I got it to work in minutes. Now, for the next challenge, I wanted a filter text box: one that will reduce the list while you type. That seemed a challenge indeed…

My problem basically is that I don’t know how to connect all the dots. Where do I put what code? I have a book-filter component which receives the filter term. It then uses sendAction() to trigger an action in my route. But then what? It’s all quite a black box.

Things that I have considered:

  • A controller for books/index. The offical docs sort of discourage the use of controllers.
  • Computed properties, but where?

I would really appreciate if someone nudged me in the right direction. Here’s some code to clarify:

//app/routes/books/index.js
export default Ember.Route.extend({

    model() {
        return this.store.findAll('book');
    },

    actions: {
        filterBooks: function (filterTerm) {
            console.log(filterTerm); //this prints whatever I have typed in the filter box
        }
    }

});
//app/templates/books/index.hbs
<h2>List</h2>

{{book-filter doFilter='filterBooks' model=model}}

<div class="row">
    {{#each model as |book|}}
        <div class="col-md-4">
            {{book-info item=book}}
        </div>
    {{/each}}
</div>
//app/components/book-filter.js
import Ember from 'ember';

export default Ember.Component.extend({
    filter: '',

    actions: {
        filter() {
            var filtertext = this.get('filter');
            this.sendAction('doFilter', filtertext);
        }
    }
});
<!--/app/templates/components/book-filter.hbs-->
<div class="row margin-bottom">
    <div class="col-md-6">
        <div class="input-group">
            <span class="input-group-addon">@</span>
            {{input value=filter class="form-control" placeholder="Filter" }}
            <span class="input-group-btn">
                <button class="btn btn-default" {{action 'filter'}}>Go!</button>
             </span>
        </div>
    </div>
</div>

#2

UPDATE: I decided to ditch the component, and get it to work in the page itself first. And it actually did work how I imagined it to do. Turns out it was that easy :slightly_smiling: The question remains: how to make this work with components?

Here’s an updated piece of the code

//app/router/book/index/js
export default Ember.Route.extend({
    model() {
        return this.store.findAll('book');
    }
});
//app/controllers/books/index/js
export default Ember.Controller.extend({
    filter: '',

    filteredBooks: Ember.computed('filter', function() {
        const filterTerm = this.get('filter');
        var model = this.get('model');

        var filtered = model.filter( function(book) {
            return book.get('title').indexOf(filterTerm) !== -1;
        });

        return filtered;
    })

});
<!--app/templates/books/index.hbs-->

<h2>List</h2>

<div class="row margin-bottom">
    <div class="col-md-6">
        <div class="input-group">
            <span class="input-group-addon">@</span>
            {{input value=filter class="form-control" placeholder="Filter" }}
        </div>
    </div>
</div>

<div class="row">
    {{#each filteredBooks as |book|}}
        <div class="col-md-4">
            {{book-info item=book}}
        </div>
    {{/each}}
</div>

#3

I sort, filter and do pagination like this:


#4

@SurfMan Thank you very much for your kind words. :slight_smile: I’m glad to hear that you learned a lot.

It is a great idea to extend that Library app and adding new features, and practicing.

I see, you finally solved your own challenge. Nice solution. Well done. Hope you enjoy learning Ember.js. :slightly_smiling:

The whole tutorial updated, and I only use ES2015 syntax everywhere: Ember.js tutorial