1

I have been through a few of those questions on Stackoverflow and found this link from a thread:http://toddmotto.com/everything-about-custom-filters-in-angular-js/ which is great but I am struggling to adapt it to what I need to do.

I am trying to implement a simple function based on it which will have a button group one which shows all results then from and to letter such as:

<button type="button" class="btn btn-primary">All</button>
<button type="button" class="btn btn-primary”>A-E</button>
  <button type="button" class="btn btn-primary">F-K</button>
    <button type="button" class="btn btn-primary">L-P</button>

However I am unable to adapt the function to perform this filter. I can only do with the basic filter by single letter.

<button type="button" class="btn btn-primary" ng-click="letter = 'C'">C</button>

I am also unable to show “all results" Here is my app code:

var app = angular.module (‘app', []);

app.controller('PersonCtrl', function () {
    this.friends = [{
        name: 'Andrew'
    },
    {
        name: 'Bob'
    },{
        name: 'Beano'
    },{
        name: 'Chris'
    }, {
        name: 'Will'
    }, {
        name: 'Mark'
    }, {
        name: 'Alice'
    }, {
        name: 'Todd'
    }];
});
  app.filter('startsWithLetter', function () {
      return function (items, letter) {
          var filtered = [];
          var letterMatch = new RegExp(letter, 'i');
          for (var i = 0; i < items.length; i++) {
              var item = items[i];
              if (letterMatch.test(item.name.substring(0, 1))) {
                  filtered.push(item);
              }
          }
          return filtered;
      };
  });

HTML CONTROLLER CODE:

<div class="container" ng-controller="PersonCtrl as person">

<ul>
        <li ng-repeat="friend in person.friends | startsWithLetter:letter">
                {{ friend }}
        </li>
</ul>
</div>

How do I adapt this to perform more specific filtering?

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
HGB
  • 2,157
  • 8
  • 43
  • 74

2 Answers2

1

You could have filtering based on the alphabet ASCII codes. On button click set the range of ASCII code using ng-click directive with - separated value like letter='65-69. Then that range will pass through the the filter, out of which first parameter is upperLimit & 2nd one is lowerLimit of the selected range. For comparing the starting variable ASCII value we could use string.charCodeAt('0') method which will return ASCII value of first character & will compare that value with the range variable inside foreach loop.

Markup

<div class="container" ng-controller="PersonCtrl as person">
    <ul>
      <li ng-repeat="friend in person.friends | startsWithLetter:letter">
        {{ friend }}
      </li>
    </ul>
    <button type="button" class="btn btn-primary" ng-click="letter=''">All</button>
    <button type="button" class="btn btn-primary" ng-click="letter='65-69'">A-E</button>
    <button type=" button " class="btn btn-primary" ng-click="letter='70-75'">F-K</button>
    <button type="button " class="btn btn-primary " ng-click="letter='76-80'">L-P</button>
</div>

Filter

app.filter('startsWithLetter', function() {
  return function(items, letter) {
    if (!letter || letter.length == 0)
      return items;
    var filtered = [],
      range = letter.split('-');
    var letterMatch = new RegExp(letter, 'i');
    for (var i = 0; i < items.length; i++) {
      var item = items[i];
      for (var j = parseInt(range[0]); j <= parseInt(range[1]); j++) {
        if (item.name.charCodeAt('0') == j) {
          filtered.push(item);
        }
      }
    }
    return filtered;
  };
});

Working PLunkr

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • Hey I am only seeing it on my phone but it looks like it's a good solution. Will test it on my laptop as soon as I get a chance. Thanks for helping me out! – HGB Sep 23 '15 at 19:45
  • @HGB did you found any problem with this? – Pankaj Parkar Sep 24 '15 at 10:34
  • 1
    All good, I just thought the "letter" rather than index is easier for me to understand/implement. thanks! – HGB Sep 24 '15 at 11:11
  • @HGB anyways Glad to help you.. Thanks :) – Pankaj Parkar Sep 24 '15 at 11:20
  • Hi Pankaj, you may be able to help with this too. I want to understand why you use `this.friends =` instead of `$scope.friends` because the use of `this` is resulting in other functions to fail for me. how do I make friends available as a service or factory for all the subsequent functions? (I am guessing) – HGB Sep 25 '15 at 10:39
  • Basically there are two way to use controller, 1. **`ControllerAs`** that uses `this` inside a controller to provide two way binding on view but for that you need to use something like ` ng-controller="PersonCtrl as person"` which will make available your `this` on controller inside `person`. 2. **Using $scope** here you will `$scope` to bind all the variable to it. And they will be available on view without any controller alias. – Pankaj Parkar Sep 25 '15 at 10:45
  • So basically if I add $scope instead of this I will need turn toLetter and from letter into variables? Or can I just switch this this.toLetter to $scope.toLetter also? – HGB Sep 25 '15 at 11:15
  • `this.toLetter` should be fine for you. – Pankaj Parkar Sep 25 '15 at 11:18
  • I am trying to change this.setLetters into $scope.setLetters = function (from,to){$scope.fromLetter. ..etc but now keep getting $scope not defined errors...:-( – HGB Sep 25 '15 at 11:27
  • Basically what I am struggling with is how to make my friends data available in the entire scope of the app to any function and I do not understand angularjs 's logic in doing this. If I leave this.toLetter as it is the filter function stops working if friends is no longer this.friends. – HGB Sep 25 '15 at 11:47
  • @HGB Seems like your solution would be create a new service. And share `friends` data among whole application.Refer here http://stackoverflow.com/a/28262966/2435473 how to make service and what it is?.Or for getting more better you open new question with detailed explaination there.. – Pankaj Parkar Sep 25 '15 at 12:31
  • Getting absolutely no where with this. Is there a simpler example? All I want is to be able to refer to the friends values from any function. Here is my horrible attempt: http://plnkr.co/edit/ZuWgHjCSGaFO51p5Y5dg?p=preview – HGB Sep 25 '15 at 14:41
  • Added another attempt here: http://plnkr.co/edit/nMgA4JxlxWvfwecPzw6b?p=preview let me know if you need me to add this to another thread. The addName function works fine but not the filter one. – HGB Sep 25 '15 at 15:17
1

You can use colons to pass multiple arguments to your filter - fromLetter and toLetter as well as your input.

<li ng-repeat="friend in person.friends | startsWithLetter:person.fromLetter:person.toLetter">
    {{ friend }}
</li>

Then you can lowercase the first letter of the string and compare this directly to fromLetter and toLetter

app.filter('startsWithLetter', function () {
    return function (items, fromLetter, toLetter) {
        var filtered = [];
        for (var i = 0; i < items.length; i++) {
            var item = items[i];
            var firstLetter = item.name.substring(0, 1).toLowerCase();
            if ((!fromLetter || firstLetter >= fromLetter)
                && (!toLetter || firstLetter <= toLetter)) {
                filtered.push(item);
            }
        }
        return filtered;
    };
});

That means that the button logic needs to be slightly more complex and set two variables:

<button type="button" class="btn btn-primary" ng-click="person.setLetters()">All</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('a','e')">A-E</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('f','k')">F-K</button>
<button type="button" class="btn btn-primary" ng-click="person.setLetters('l','p')">L-P</button>                                                             

and on your controller:

this.setLetters = function(from, to){
    this.fromLetter = from;
    this.toLetter = to;
};

JSFiddle

sheilak
  • 5,833
  • 7
  • 34
  • 43
  • Event Better Sheilak! Thanks a lot. I just need to figure out how to turn this into a more complex datasource, but that is another thread :-) – HGB Sep 24 '15 at 10:04
  • Hi Sheilak I am trying to understand what "this" refers to in your code. I wanted to change this to $scope to make it available throughout the app, but it stops working. What does this "this" mean? – HGB Sep 25 '15 at 09:57
  • Here is a link for some background about [$scope and controller as syntax.](http://stackoverflow.com/questions/16619740/angular-should-i-use-this-or-scope) "this" refers to the controller. I used controller as syntax because I was following the pattern you were using in your question. You can easily switch over to $scope - here is [a JsFiddle](http://jsfiddle.net/sheilak/95boLxjp/) so you can compare – sheilak Sep 25 '15 at 16:29