Search code examples
angularjsangularjs-ng-repeatng-optionsangular-filters

angular ng-options select filter ng-repeat


I am rewriting an angular select option, previously I was using a bootstrap btn-group class with numerous li classes, which used ng-click to set a filter in my ng-repeat list which worked perfectly. Like so:

<li role="menuitem">
   <a ng-click="myFilter = { moving: true }">Delivery &amp; Removals</a>
</li>

However, after some feedback, I have been asked to change it to a <select> with <option> set up, so to reflect the selected option.

I have added a list to my controller scope, like so:

$scope.taskCategories = [
    {'cat': 'Moving & Delivery', 'filter': 'moving: true'},
    {'cat': 'DIY', 'filter': 'DIY: true'},
    {'cat': 'Marketing', 'filter': 'marketing: true' }
]

Here is the select

{{ selectedCat.filter }}
<select ng-model="selectedCat" ng-value="x.filter" ng-options="x.cat for x in taskCategories">
  </select>

Here is my ng-repeat

data-ng-repeat="task in vm.tasks | filter:search | filter:myFilter | filter: { filter: selectedCat.filter } : true | orderBy:predicate:reverse | filter:x as results" 

To give a bit of relevance, my ng-click filters work like so:

ng-click="myFilter = { moving: true }"

However, when I click on one of my select values, which are ng-repeating through the $scope.taskCategories just fine, my ng-repeat returns 0 results, which is not correct.

If anyone could give me any pointers on where I am going wrong, I would greatly appreciate it. Thanks in advance! :)


Solution

  • You can create a custom filter and search by the property inside the object, as the following:

    (function(angular) {
      'use strict';
    angular.module('ngRepeat', ['ngAnimate'])
    .controller('repeatController', function($scope) {
      $scope.tasks = [
      			{
            'created': "2016-07-02T21:01:56.095Z",
            'description':"hang it",
            'dueDate':"2016-07-02T22:00:00.000Z",
            'inPersonTask':true,
            'isCurrentUserOwner':false,
            'moving':true,
            'profileImageURL':"modules/users/client/img/profile/default.png",
            'statusAssigned':false,
            'statusClosed':false,
            'statusOpen':true,
            'taskLocation':"eerywhere",
            'title':'example 3'
            },
            {
            'created': "2016-07-02T21:01:56.095Z",
            'description':"hang it",
            'dueDate':"2016-07-02T22:00:00.000Z",
            'inPersonTask':true,
            'isCurrentUserOwner':false,
            'DIY':true,
            'profileImageURL':"modules/users/client/img/profile/default.png",
            'statusAssigned':false,
            'statusClosed':false,
            'statusOpen':true,
            'taskLocation':"the world",
            'title':'example 2'
            },
            {
            'created': "2016-07-02T21:01:56.095Z",
            'description':"hang it",
            'dueDate':"2016-07-02T22:00:00.000Z",
            'inPersonTask':true,
            'isCurrentUserOwner':false,
            'marketing':true,
            'profileImageURL':"modules/users/client/img/profile/default.png",
            'statusAssigned':false,
            'statusClosed':false,
            'statusOpen':true,
            'taskLocation':"the world",
            'title':'example 3'
            }
      ];
      $scope.taskCategories = [
            {'cat': 'Moving & Delivery', 'filter': 'moving: true'},
            {'cat': 'DIY', 'filter': 'DIY: true'},
            {'cat': 'Marketing', 'filter': 'marketing: true' }
        ];
    })
    
      .filter('customFilter', function() {
        return function(items, search) {
          if (!search) {
            return items;
          }    
    
          return items.filter(function(element) {
           // Ex: moving: true, becomes just 'moving'
           return Object.getOwnPropertyNames(element).find(x => x == search.substring(0, search.indexOf(':')));
          });
        };
      });
    })(window.angular);
    .example-animate-container {
      background:white;
      border:1px solid black;
      list-style:none;
      margin:0;
      padding:0 10px;
    }
    
    .animate-repeat {
      line-height:30px;
      list-style:none;
      box-sizing:border-box;
    }
    
    .animate-repeat.ng-move,
    .animate-repeat.ng-enter,
    .animate-repeat.ng-leave {
      transition:all linear 0.5s;
    }
    
    .animate-repeat.ng-leave.ng-leave-active,
    .animate-repeat.ng-move,
    .animate-repeat.ng-enter {
      opacity:0;
      max-height:0;
    }
    
    .animate-repeat.ng-leave,
    .animate-repeat.ng-move.ng-move-active,
    .animate-repeat.ng-enter.ng-enter-active {
      opacity:1;
      max-height:30px;
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>Example</title>
      <link href="animations.css" rel="stylesheet" type="text/css">
       <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
       <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular-animate.min.js"></script>
    </head>
    
    <body ng-app="ngRepeat">
      <div ng-controller="repeatController">
        <!-- list of tasks /-->
        <h3>List of tasks, without filter</h3>
        <ul class="example-animate-container">
          <li class="animate-repeat" ng-repeat="task in tasks">[{{$index + 1}}] {{ task.title }}, {{ task.taskLocation }}</li>
        </ul>
        <!-- list of tasks with filter /-->
        <h3>List of tasks with filter -- results are not showing</h3>
        <p>{{ selectedCat }}</p>
        <select ng-model="selectedCat" ng-options="x.cat for x in taskCategories" ng-value="x.filter">
        </select>
        <ul>
          <li class="animate-repeat" ng-repeat="task in tasks | customFilter: selectedCat.filter">
            [{{$index + 1}}] {{ task.title }}, {{ task.taskLocation }}</li>
        </ul>
      </div>
    </body>
    
    </html>