0

I am working on chaining multiple filters, but while thinking it through i realised that it creates an extreme amount of code (redudancy would be the best term in this use-case), which made me wonder if this could be done more dynamically/generalized. Basically i have 5-6 dropdown menu where a user can select one or more options to filter the data with. I have made this based on one dropdown menu but i want to extend this further. In this code sample i have one dropdown menu which sorts out based on one column.

JavaScript:

<script>
'use strict';
var App = angular.module('App',['ngResource','App.filters']);

App.controller('ExerciseCtrl', ['$scope','$http', function($scope, $http) {

    $scope.selectedMainMuscle = [];

    $http.get('/rest/exercises/')
       .then(function(res){
          $scope.exercises = res.data;                
    });

    $scope.orderProp = 'name';    

    $http.get('/rest/muscles/')
       .then(function(res){
          $scope.muscles = res.data;                
    });    

    $scope.isChecked = function () {
         if (_.contains($scope.selectedMainMuscle, this.muscle.id)) {
             return 'glyphicon glyphicon-ok pull-right';
         }
         return false;
     }; 

     $scope.setSelectedMainMuscle = function () {
         var id = this.muscle.id;
         if (_.contains($scope.selectedMainMuscle, id)) {
             $scope.selectedMainMuscle = _.without($scope.selectedMainMuscle, id);
         } else {
             $scope.selectedMainMuscle.push(id);
         }
         return false;
     };
}]);

angular.module('App.filters', []).filter('mainMuscleFilter', [function () {
    return function (exercises, selectedMainMuscle) {
         if (!angular.isUndefined(exercises) && !angular.isUndefined(selectedMainMuscle) && selectedMainMuscle.length > 0) {
             var tempClients = [];
             angular.forEach(selectedMainMuscle, function (id) {
                 angular.forEach(exercises, function (exercise) {
                     if (angular.equals(exercise.main_muscle.id, id)) {
                         tempClients.push(exercise);
                     }
                 });
             });
             return tempClients;
         } else {
             return exercises;
         }
     };
 }]);
 </script>

HTML:

<div class="btn-group" ng-class="{open: dd2}">
    <button type="button" class="btn btn-default dropdown-toggle" ng-click="dd2=!dd2">Main muscle <span class="caret"></span></button>
    <ul class="dropdown-menu">
        <li ng-repeat="muscle in muscles">
            <a href ng-click="setSelectedMainMuscle()">{%verbatim%}{{muscle.name}}{%endverbatim%} <span data-ng-class="isChecked()"></span></a>
        </li>
    </ul>
</div>    
<table class="table table-hover" >
    <tr><td><strong>Name</strong></td><td><strong>Main muscle</strong></td><td><strong>Equipment</strong></td></tr>
    <tr ng-repeat="exercise in filtered = (exercises | mainMuscleFilter:selectedMainMuscle)">
        {%verbatim%}<td>{{exercise.name}}</td><td>{{exercise.main_muscle.name}}</td><td>{{exercise.equipment.name}}</td>{%endverbatim%}
    </tr>
</table>
4
  • Can you explain a little more and give some example data? The terminology in your code makes it a little hard to discern. For instance you have a singular 'selectedMainMuscle', but that is an array. Does each exercise have only a single main_muscle and you want to be able to check several main muscles and see all the exercises that have any of the options as their main_muscle? Does your code work and you're just looking for a different way? Commented Apr 16, 2014 at 17:31
  • Basically each exercise is described by 6 columns. In this particular example i have given in code, i am attempting to filter the exercises based on which muscle it focuses on, hence mainMuscle. The muscle array consist of all the muscles, which is primarily used in the dropdown list. selectedMainMuscle should have been selectedMainMuscles. Im sorry for this typo. Commented Apr 16, 2014 at 17:40
  • So you're going to have 4-5 more drop-down menus for the different columns in each exercise to allow filtering on any/all of them and you don't want to create separate filters for each one? Commented Apr 16, 2014 at 17:43
  • Thats basically what im attempting. I have 4-5 columns, and i wish to be able to filter these in the same manner as i am using right now. Commented Apr 16, 2014 at 17:44

1 Answer 1

1

I would do all the checks in one filter, I don't see how a mainMuscleFilter would be reusable enough to warrant separation, let alone inclusion in a separate module. You can generalize your methods to toggle the inclusion of an id in an array and to check for the inclusion though:

$scope.selected = {
    muscle: [],
    equipment: []
};

$scope.isChecked = function (arr, id) {
     if (_.contains(arr, id)) {
         return 'glyphicon glyphicon-ok pull-right';
     }
     return false;
 }; 

 $scope.toggleInclusion = function (arr, id) {
     var index = arr.indexOf(id);
     if (index >= 0) {
         arr.splice(index, 1);
     } else {
         arr.push(id);
     }
     return false;
 };

HTML:

<li ng-repeat="muscle in muscles">
    <a href ng-click="toggleInclusion(selected.muscle, muscle.id)">
        {{muscle.name}}
        <span data-ng-class="isChecked(selected.muscle, muscle.id)"></span>
    </a>
</li>
Sign up to request clarification or add additional context in comments.

3 Comments

So basically my filter should iterate through the content of the selected array?
I was thinking iterate through exercises and have a separate check for each array in the selected object. You don't have to make it generic, but you could have a local function that you pass the id to check and the array to check for the contents for like isNotExcluded(array, id) and do isNotExcluded(selected.muscles, exercise.muscle.id) && isNotExcluded(selected.equipment, exercise.equipment.id)
One last thing, how do i allow a function call inside of my module, which is made in the scope of my controller? I am referring to the isNotExcluded which i have defined.

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.