Filtering the table

Use actions from our D3 chart to filter down our table data.


Now that we've made our bar chart component follow the data-down-actions-up pattern, we can make it interact with other parts of our application.

Right now clicking a bar updates properties on our controller, which are all bound to the URL. Let's use these properties to filter down the data in the posts table below our charts.

If we come to our posts template and we scroll down to our table, we see that it's iterating over the posts array. In our controller, that array is currently our model being sorted by the postsSorting array.

So let's rename this to sortedPosts and we'll define a new posts property that is an Ember.computed property that depends on sortedPosts. And first this will just return the sortedPosts array.

Okay everything still works, and now let's work on getting this posts array to filter down based on our selected property of selectedAuthor.

So we'll add selectedAuthor as a dependency, we'll get it right here, and then we want to filter this array. Now for each post, we want to check if we do have a selectedAuthor, then we only want to match posts whose author is equal to that selectedAuthor. Otherwise, we'll just pass in true, so that none of the posts get filtered out if there's no selectedAuthor.

sortedPosts: Ember.computed.sort('model', 'postsSorting'),

posts: Ember.computed('sortedPosts.[]', 'selectedAuthor', function() {
  let selectedAuthor = this.get('selectedAuthor');

  return this.get('sortedPosts')
    .filter(post => selectedAuthor ? (post.get('author') === selectedAuthor) : true);

Let's save this and try it out. Now we see all the data, but if we select an author, our table filters down to the selected author. And when we de-select, it goes back to the entire data set. Pretty cool! And all of this is still driven by the URL as well - so if we hit back or forward, we see that all of our data is kept in sync.

This chart is now really acting as a spiffy radio button selector for the data in our table, and this is the sort of thing that D3 empowers you to do. Whenever you're building UI interactions that use standard things like form elements, try to think if this is an opportunity to communicate some new insight to your users by coding a small visualization. Our charts here make it easy to see interesting points in our data set, and this is really what data visualization is all about.

Ok, so this chart is correctly filtering our table, but we have a small bug. If we select an author and then reload the page, our bar charts have all changed. This is because the data we're passing into our charts is based off of the posts property; and now that our page is being initially rendered with a starting value for selectedAuthor, from the query param, the first time our charts render, they're rendering based off of that filtered dataset.

Now the table still works, and if we were to click on this author, the table would go back to the full dataset. But our bar charts are not dynamically re-rendering based on changing data. And this is just because we haven't coded this yet in our bar charts. They do respond to changes in the selected label, but they don't respond to changes in the selected data array.

Now we can put in a short-term fix here. If we come back to our controller, we can see that these three computed properties that we're using to power our bar charts are all based on the posts array. So if we just change this to the unfiltered model array

postsByAuthor: groupBy('model', 'author'),

postsByCategory: groupBy('model', 'category'),

commentsData:'model', ...

and come back, now if we select a bar and reload, the initial render works, because the bar charts' data is never changing.

We'll tackle making our bar charts dynamic in the next video, but for now, let's just get the rest of the charts filtering our table.

Let's come back to our controller, and we'll go ahead and add the selectedCategory and the selectedPost. And we'll add two more filters here, one for selectedCategory and one for selectedPost. And this says if the post's category is equal to the selectedCategory, and this one is if the post's title is equal to the selectedPost property.

posts: Ember.computed('sortedPosts.[]', 'selectedAuthor', 'selectedCategory', 'selectedPost', function() {
  let selectedAuthor = this.get('selectedAuthor');
  let selectedCategory = this.get('selectedCategory');
  let selectedPost = this.get('selectedPost');

  return this.get('sortedPosts')
    .filter(post => selectedAuthor ? post.get('author') === selectedAuthor : true)
    .filter(post => selectedCategory ? post.get('category') === selectedCategory : true)
    .filter(post => selectedPost ? post.get('title') === selectedPost : true);

Save this, come back, and now the author and the category filter down the table; and we can also click on a single title here. And of course if we select filters that return no results, the table is empty. So this is pretty cool. And again, all of this works with the URL. I'm going back here, and both the table and the charts are updating; and if I have Kathryne selected with all her Programming posts, we see that in the table; and if I refresh, then all the chart state and the table state is correct. So this is pretty cool!

In the next video, we'll make our bar charts dynamically respond to changing data.


Send us a tweet:

Or ask us in Inside EmberMap, our private Slack workspace for subscribers.