1

I'm a newcomer to Angular/JS so please be kind ... I'm having a problem (probably with myself trying to wrap my brain around Angular) with some code where I want to use two different filters (I think) on a dataset with ng-repeat. Firstly here is a screen shot of the html form items and data output I am working with;

Webpage

Here is the basic (stripped down) HTML code for the setup above;

<div ng-controller="customersCrtl">

      Records Per Page:
      <select ng-model="entryLimit" class="form-control">
        <option>50</option>
        <option>100</option>
        <option>250</option>
        <option>500</option>
        <option>1000</option>
      </select>

      Record Type:
      <select ng-model="entryType" class="form-control">
        <option>All</option>
        <option>Baptism</option>
        <option>Marriage</option>
        <option>Burial</option>
      </select>

      Filter Text:
      <input type="text" ng-model="search" ng-change="filter()" placeholder="Filter" class="form-control" />

      Filtered {{ filtered.length }} of {{ totalItems }} Total Records

      <div ng-show="filteredItems > 0">
        <table>
          <thead>
            <th>Event Date <a ng-click="sort_by('eventDate');">sort</a></th>
            <th>Event Type <a ng-click="sort_by('type');">sort</a></th>
            <th>Indivdual(s) <a ng-click="sort_by('name');">sort</a></th>
            <th>Location <a ng-click="sort_by('location');">sort</a></th>
            <th></th>
          </thead>
          <tbody>
            <tr ng-repeat="data in filtered = (list | filter:search | orderBy : predicate :reverse) | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">
              <td>{{data.eventDate | date:'mediumDate'}}</td>
              <td>{{data.type}}</td>
              <td>{{data.name}}</td>
              <td><a href="#">{{data.location}}</a></td>
              <td><a href="#">View Record</a></td>
            </tr>
          </tbody>
        </table>
      </div>

... and here is the associated Angular JS code I currently have;

var app = angular.module('myApp', ['ui.bootstrap']);

app.filter('startFrom', function() {
    return function(input, start) {
        if(input) {
            start = +start; //parse to int
            return input.slice(start);
        }
        return [];
    }
});
app.controller('customersCrtl', function ($scope, $http, $timeout) {
    $http.get('ajax/getMarkers.php').success(function(data){
        $scope.list = data;
        $scope.currentPage = 1; //current page
        $scope.entryLimit = 50; //max no of items to display in a page
        $scope.entryType = 'All'; //Record type to display in a page
        $scope.filteredItems = $scope.list.length; //Initially for no filter
        $scope.totalItems = $scope.list.length;
    });
    $scope.setPage = function(pageNo) {
        $scope.currentPage = pageNo;
    };
    $scope.filter = function() {
        $timeout(function() {
            $scope.filteredItems = $scope.filtered.length;
        }, 10);
    };
    $scope.sort_by = function(predicate) {
        $scope.predicate = predicate;
        $scope.reverse = !$scope.reverse;
    };
});

getMarkers.php in the above Angular code snippet returns JSON results formatted like so;

{"id":"646","eventDate":"1576-05-13","name":"John Phillip","type":"Baptism","churchName":"St. Marys","locationid":"563","location":"Swainswick, Somerset, UK","lat":"51.414211","lng":"-2.351418"},
{"id":"647","eventDate":"1577-07-01","name":"Jane Volantyne","type":"Baptism","churchName":"St. Mary the Virgin","locationid":"564","location":"Horsham, Sussex, UK","lat":"51.059750","lng":"-0.330879"},
{"id":"132","eventDate":"1634-05-09","name":"Katherine Stanley","type":"Burial","churchName":"St. James","locationid":"567","location":"Titsey, Surrey, UK","lat":"51.276505","lng":"0.018909"}
... etc. etc.

This currently works in so-far-as if a user types something in the "Filter Text" box, the table updates to only show entries that match the user text.

This is fine, but what I also want to be able to do is use the drop down "Record Type" box (with the defined entries All, Baptism, Burial, Marriage) to only show/filter the records with that particular "Event Type" in the table. Is this even possible? Can you apply two concurrent filters to an ng-repeat in Angular, because I've tried and failed several times and am on the verge of giving up!!!

Am I asking something stupidly difficult or stupidly easy?

1 Answer 1

0

Yes, its very possible to filter the table based on multiple conditions, You could add a filter function to the table as:

<tr ng-repeat="data in filtered = (list | filter:filterEvents | orderBy : predicate :reverse) | startFrom:(currentPage-1)*entryLimit | limitTo:entryLimit">
     <td>{{data.eventDate | date:'mediumDate'}}</td>
     <td>{{data.type}}</td>
     <td>{{data.name}}</td>
     <td><a href="#">{{data.location}}</a></td>
     <td><a href="#">View Record</a></td>
</tr>

Basically, $scope.filterEvents is called every time the table is populated and you could filter out the required items using this in the controller:

$scope.filterEvents = function(item){
//Here item is the array element from the table
 which is automatically passed in the filter function.

 return item.type.toLowerCase().indexOf($scope.entryType.toLowerCase()) != -1 || 
        item.name.toLowerCase().indexOf($scope.search.toLowerCase()) != -1 
}

Where , $scope.entryType is the option selected in the dropdown and $scope.search is the keyword for searching.

Ps: You would need to remove the ng-change=filter() from search textbox and handle the return if $scope.entryType = "All"

Sign up to request clarification or add additional context in comments.

4 Comments

thanks for the reply and I take on board what you've suggested, but making those changes ends up with no results being listed on first loading of the page ...
Do you see any error on console? Also, did you remove this: ng-show="filteredItems > 0"
$scope.search is undefined
Add $scope.search = ""; at starting of the controller

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.