Search code examples
javascriptjsonangularjsmappingangular-filters

How can I associate a number to a specific string and use that string to filter an iteration in AngularJS?


I am new to AngularJS and I'm having problems doing a reusable generic filter.

Let's say I have a colors, types, and list objects as seen below (New JSON). I want to make a generic filter that will take colors and types objects and filter the list object without having to use the string match as filter.

For now I did specific filters by strings as seen below.

I will have a lot of information in these objects and I don't want to update the controller each time a new property is being included in the JSON.

How do I associate the number to its specific string value?

Old JSON

[
    {
        "id": 1,
        "name": "Spike",
        "type": "dog",
        "color": "gray"
    },
    {
        "id": 2,
        "name": "Tom",
        "type": "cat",
        "color": "blue"
    },
    {
        "id": 3,
        "name": "Butch",
        "type": "cat",
        "color": "black"
    }
]

New JSONs

// colors
[
    {"gray": 1},
    {"black": 2},
    {"blue": 3},
]

// types

[
    {"dog": 1},
    {"cat": 2}
]

// data list
[
    {
      "id": 1,
      "type": 1,
      "name": "Spike",
      "color": 1
    },
    {
      "id": 2,
      "type": 2,
      "name": "Tom",
      "color": 3
    },
    {
      "id": 3,
      "type": 2,
      "name": "Butch",
      "color": 2
    }
]

Filters

        <table class="table table-bordered table-condensed table-striped table-hover">
            <thead>
                <tr>
                    <th>
                        <a>
                            Filters:
                        </a>
                    </th>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="item in typeItems">
                    <td>
                        <label class="check">
                            <input type="checkbox" ng-model="typeFilterItems[item.type]">{{item.type}}
                        </label>
                    </td>
                </tr>
                <tr ng-repeat="item in colorItems">
                    <td>
                        <label class="check">
                            <input type="checkbox" ng-model="colorFilterItems[item.color]">{{item.color}
                        </label>
                    </td>
                </tr>
            </tbody>
        </table>

List

        <table class="table table-bordered table-condensed table-striped table-hover header-fixed">
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Type</th>
                    <th>Color</th>
                    <th>Name</th>
                </tr>
            </thead>
            <tbody>
                <tr class="list" ng-repeat="item in animals | filter:typeFilter | filter:colorFilter">
                    <td>{{item.id}</td>
                    <td>{{item.type}}</td>
                    <td>{{item.color}}</td>
                    <td>{{item.name}}</td>
                </tr>
            </tbody>
        </table>

Controller

    Animals.list().then(function (data) {
        $scope.animals = data;
    });

    $scope.colorFilterItems = { 'black': true, 'gray': false, 'blue': false }; // doing this to have a predefined filter selection ... for now
    $scope.colorItems = [{ name: 'black' }, { name: 'gray' }, { name: 'blue' }];

    $scope.colorFilter = function (item) {
        return $scope.colorFilterItems[item.color]
    };

    $scope.typeFilterItems = { 'dog': true, 'cat': false }; // doing this to have a predefined filter selection ... for now
    $scope.typeItems = [{ name: 'black' }, { name: 'gray' }, { name: 'blue' }];

    $scope.typeFilter = function (item) {
        return $scope.typeFilterItems[item.type]
    };

Solution

  • Since no one answered I eventually found a solution.

    The answer to all this is to use lodash directly inside the service and create a filter method inside the promise that looks for the selected property inside the filter objects and compares them to the data we want to display.

    filterAnimals = () => {
        intersectedResults =
        _.filter(animals,(animal: iAnimal) => {
            var colors = _.find(colorLabels,(item: iFilter) => {
                return (animal.color ? item.label === animal.color : item.label == null) && item.selected;
            });
            var types = _.find(typeLabels,(item: iFilter) => {
                return (animal.type ? item.label === animal.type : item.label == null) && item.selected;
            });
            return colors && types;
        });
        return data;
    };
    

    After doing this I acces the filterAnimals() function from the controller and bind the checkbox filters to my data. When doing an ng-change on the checkbox this function executes and checks the filters against the data and it shows the data I need.