Skip to content

Latest commit

 

History

History
164 lines (119 loc) · 6.47 KB

filters.md

File metadata and controls

164 lines (119 loc) · 6.47 KB

#Filters!

Filters in AngularJS are awesome. They allow you to do a lot of really cool things with data representation and visualization, really quickly and easily.

##What are filters in AngularJS?

Filters in AngularJS format expressions. Usually, you use them in the view. While it is possible to filter in your controller, I have basically never seen that, so we'll focus on using filters in your view.

##General formatting syntax

Filters look like this: {{ expressionToFilter | filterFunction:argument1:argument2 }}.

expressionToFilter is the expression we are going to filter/format; typically, this is either an array or a single expression/argument, like a string or an object.

filterFunction is either one of several different filter functions that come with AngularJS, or a function that you have created somewhere else. That's right, you can create custom filters!

Sometimes, filters have arguments, and you add them by appending :ARGUMENT to the filter function. We'll look at some examples of that shortly.

There is documentation for the different filter functions that come with AngularJS right out of the box here, and it is extensive.

There are a lot of different kinds of filters that are very useful, but particularly good ones to know include filter:foo, which does not display expressions that do not include foo; this looks like the standard search you are used to, and in fact we implement this filter in phonecat to search for phone types. Other important filters include orderBy:foo, date, and uppercase. In my experience, I have also written filters that will capitalize the first letter of a string and make the rest of the string lowercase.

##Filtering to change the data display

So, filters are a kind of formatting; what might we want to format in our app? HINT: date objects! YAAAAAY!

Go to home.html and find the place where we put post.date. Replace that line of code with <small>{{post.date | date:'EEEE'}}</small> and then refresh it in the browser. That's pretty cool, huh? You can find other formats to use instead of this EEEE format here.

##Adding a broad search

Let's add a search that will let us look at the content in our posts.

Near the top of home.html but still inside your ng-controller, add the line broad search: <input type="text" ng-model="search">. Next, find the line of code that includes ng-repeat: post in posts and update the ng-repeat so that it reads ng-repeat: post in posts | filter:search:strict.

What we just did was create a text input with an ng-model called search. We then added a filter to our post repeater telling it to only include posts that have our search term, though we did not specify whether we wanted it to look for this search term in the title, the body, or somewhere else. Take a little time to try different search terms and play with this feature. Think about how hard it would be to implement this feature with a regular Rails app.

##Adding a slightly more specific search

Let's get more specific: let's add a search bar that lets us look just at the titles of our posts, just in case we remember what that awesome post was called but not when it was posted.

Add another input with a more specific ng-model. It should look like title search: <input type="text" ng-model="search.title">.

Okay, that should be it! You should be able to go to your refreshed browser and now have a search bar that only looks at values in the title.

##Just searching tags

So, we're going to be using tags on our posts, and I beeeeet that we'll be able to filters to sort by tags.

Standard sort-by-tags UI usually involves clicking on tags in a list of tags, so let's start by creating this list. In layout.js, we're going to create a new array to hold our tags in our controller with $scope.tagArray = [];. Let's also reuse some of the code we used to toggle tags in our model. We'll grab parts of $scope.toggleIds, like so:

$scope.addTag = function(id) {
  i = $scope.tagArray.indexOf(id);
  if(i == -1) {
    $scope.tagArray.push(id);
  } else {
    $scope.tagArray.splice(i, 1); 
  }
}

And now, we'll copy some of the view code we created to show our tags in order to create a tag bank we can select. Add the following code near the top of home.html (near the top, but still in the ng-controller):

<span ng-repeat="tag in tags">
  <input type="checkbox" value="tag.id" ng-click="addTag(tag.id)">{{tag.name}}</input>
</span>

So right now, we have a new array called tagArray, and we can add and remove tags from it by selecting the checkboxes. We can test this theory by printing the tagArray with a {{tagArray}} somewhere in the view.

Custom filter syntax looks like this:

moduleName.filter('filterName', function() {
  return function(variableNameForWhatWe'reFiltering, anyAdditionalParams) {
    return variableNameForWhatWe'reFiltering.filter(function(variableNameForJustOne) {
      //condition
        //return true if we want it to show up in the view
      //else
        //return false, and it won't show in the view
    });
  };
});

We'll follow this syntax to create a filter to only show posts that include the tags that we put in. To do this, we'll add the following block of code inside the layout.js file, but NOT within the controller--this should go at the very bottom of the file, outside the controller.

homeControllerModule.filter('selectedTags', function() {
  return function(posts, tagArray) {
    return posts.filter(function(post) {
      for (var i in posts) {

        // shows all posts if no tags have been added to the array
        if (tagArray.length == 0) {
          return true;
        } else {

          // remember that .indexOf returns -1 if the item is not in the array.
          // this filter returns true if the tag IS in the array.
          if (tagArray.indexOf(post.tag_ids[i]) != -1) {
            return true;
          }
        }
      }

      // returns false if it hasn't already returned true
      return false;

    });
  };
});

Now, if we go to the home.html and update the `ng-repeat="post in posts" line and update it to the following:

<div ng-repeat="post in posts | filter:search:strict | selectedTags:tagArray:true">

we should now be able to filter based on both the words we provide in the inputs and based on tags we select.