Search code examples
javascriptangularjsangular-filters

Filter "custom values" in AngularJS ng-repeat


I need to filter a list by their category, but each of these categories are custom, every user can write any category they want in the list.

I tried to make a list with ng-repeat in which I filtered all the duplicated values (In the code below is the unique:'Category' part), and I gave them the Category name as the value to filter, also I added an "All" category to show all the elements:

<ul class="categoriesList">
  <li>
    <label>
      <input type="radio" ng-model="searchCategory.Category" value=""> All
    </label>
  </li>
  <li ng-repeat="x in myList | unique:'Category'">
    </label>
      <input type="radio" ng-model="searchCategory.Category" value="{{x.Category}}"> {{x.Category}}
    </label>
  </li>
</ul>

But this approach isn't working. I've made a Plunker as example: Here is my plunker

I need to be able to add any category I want in the json example, and to be able of filter them. Thanks in advance.


Solution

  • OK the issue with your code was just that your property searchCategory was not defined on the $scope. Adding $scope.searchCategory = {}; to your controller will solve the issue. And the reason behind this is that ng-repeat creates its own child scope. Below is a snippet with the working solution.

    Also one more thing was missing i.e you need to have the same group for all the radio buttons so that only one is selected at a time and that you do by adding name='filter' attribute all radio button.

    var app = angular.module('app', []);
    
    //duplicates filter
    app.filter('unique', function() {
      return function(items, filterOn) {
        if (filterOn === false) {
          return items;
        }
    
        if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
          var hashCheck = {},
            newItems = [];
          var extractValueToCompare = function(item) {
            if (angular.isObject(item) && angular.isString(filterOn)) {
              return item[filterOn];
            } else {
              return item;
            }
          };
          angular.forEach(items, function(item) {
            var valueToCheck, isDuplicate = false;
            for (var i = 0; i < newItems.length; i++) {
              if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
                isDuplicate = true;
                break;
              }
            }
            if (!isDuplicate) {
              newItems.push(item);
            }
          });
          // items = newItems;
        }
        return newItems;
      };
    });
    
    app.controller('MainCtrl', function($scope) {
      $scope.searchCategory = {};
      $scope.myList = [{
          "Category": "My custom category",
          "Title": "Title example",
          "Comments": "Example comments"
        },
        {
          "Category": "My custom category",
          "Title": "My cat is named George",
          "Comments": "Example comments"
        },
        {
          "Category": "My custom category",
          "Title": "Hocus pokus",
          "Comments": "Example comments"
        },
        {
          "Category": "My custom category",
          "Title": "Tyrion Lannister must have been king",
          "Comments": "Example comments"
        },
        {
          "Category": "My custom category",
          "Title": "some text",
          "Comments": "Example comments"
        },
        {
          "Category": "Some new category",
          "Title": "7 projects going LIVE now",
          "Comments": "Example comments"
        },
        {
          "Category": "Some new category",
          "Title": "Batman vs Superman was a good movie",
          "Comments": "Example comments"
        },
        {
          "Category": "Some new category",
          "Title": "Youtube channel projects",
          "Comments": "Example comments"
        },
        {
          "Category": "Some new category",
          "Title": "Some project name",
          "Comments": "Example comments"
        },
        {
          "Category": "Some new category",
          "Title": "projects (more)",
          "Comments": "Example comments"
        },
        {
          "Category": "A different category",
          "Title": "Remember, remember the fifth of november",
          "Comments": "Hello there!"
        },
        {
          "Category": "A different category",
          "Title": "It's night, electric night",
          "Comments": "General Kenobi"
        },
        {
          "Category": "Custom category",
          "Title": "project name again",
          "Comments": "Example comments"
        }
      ];
    
    });
    <!DOCTYPE html>
    <html ng-app="app">
    
    <head>
      <meta charset="utf-8" />
      <title>AngularJS Filter with custom values</title>
      <script>
        document.write('<base href="' + document.location + '" />');
      </script>
      <link rel="stylesheet" href="style.css" />
      <script data-require="[email protected]" src="https://code.angularjs.org/1.4.12/angular.js" data-semver="1.4.9"></script>
      <script src="app.js"></script>
    </head>
    
    <body ng-controller="MainCtrl">
      <ul class="categoriesList">
        <li>
          <label>
              <input name="filter" type="radio" ng-model="searchCategory.Category" ng-value=""> All
            </label>
        </li>
        <li ng-repeat="x in myList | unique:'Category'">
          <label>
              <input name="filter" type="radio" ng-model="searchCategory.Category" ng-value="x.Category"> {{x.Category}}
            </label>
        </li>
      </ul>
    
      <div class="wrapper" ng-repeat="y in myList | filter:searchCategory:true">
        <ul class="click-text">
          <li>{{y.Title}} - {{y.Comments}}</li>
        </ul>
      </div>
    </body>
    
    </html>

    Hope this helps :)