0

My aim is to replace the teacher-id(f_teacher) of one outputted array with the teacher name of another array. I wrote a custom filter, that should do the job:

angular.module('core')
.filter('replaceId', function () {                   //filter, which replaces Id's of one array, with corresponding content of another array
    return function (t_D, s_D, t_prop, s_prop) {     //data of target, data of source, target property, source property
        var replacment = {};
        var output = [];
        angular.forEach(s_D, function (item) {
            replacment[item.id] = item[s_prop];      //replacment - object is filled with 'id' as key and corresponding value
        });
        angular.forEach(t_D, function (item) {
            item[t_prop] = replacment[item[t_prop]]; //ids of target data are replaced with matching value
            output.push(item);
        });
        return output;
    }
});

I use a 'ng-repeat' like this:

<tr ng-repeat="class in $ctrl.classes | filter:$ctrl.search | replaceId:$ctrl.teachers:'f_teacher':'prename' | orderBy:sortType:sortReverse">
    <td>{{class.level}}</td>
    <td>{{class.classNR}}</td>
    <td>{{class.f_teacher}}</td>
</tr>

But it only outputs an empty column. Now the strange thing: If I follow the steps with the debugger, it works for the first time the filter is performed. But when it is performed a second time it outputs an empty column.

I noticed that the returned object of the filter overwrites the $ctrl.classes - array, but normally this shouldn't be the case?

Here is a plnkr: https://plnkr.co/edit/EiW59gbcLI5XmHCS6dIs?p=preview

Why is this happening?

Thank you for your time :)

JoCa
  • 1,045
  • 9
  • 14
  • can you reproduce the issue in a plunker? Your filter is setting fields directly on the objects in `$ctrl.classes`. If you don't want it to change `$ctrl.classes` then you could do something like `angular.copy()` the objects in it. – rob Jul 05 '16 at 15:59
  • I added a plnkr(see above). Okay, but I use other custom filters, which work on the same principle (modify the array and return the modified array) and they don't overwrite the scope. Why does this custom filter do that? – JoCa Jul 05 '16 at 19:24

1 Answers1

0

The first time through your filter the code takes the f_teacher id and replaces it with the teacher name. The second time through it tries to do the same thing except now instead of getting a teachers ID in f_teacher it finds the teacher's name so it doesn't work. You could fix it by making a copy of the classes instead of modifying them directly. e.g.

angular.forEach(t_D, function (item) {
    var itemCopy = angular.copy(item);
    itemCopy[t_prop] = replacment[itemCopy[t_prop]];
    output.push(itemCopy);
});

https://plnkr.co/edit/RDvBGITSAis3da6sWnyi?p=preview

EDIT

Original solution will trigger an infinite digest because the filter returns new instances of objects every time it runs which will cause angular to think something has changed and retrigger a digest. Could you just have a getter function that gets a teachers name instead of using a filter?

$scope.getTeacherName = function(id) {
  var matchingTeachers = $scope.teachers.filter(function(teacher) {
    return teacher.id == id;
  })

  //Should always be exactly 1 match.
  return matchingTeachers[0].prename;
};

And then in the HTML you could use it like

<tr ng-repeat="class in classes">
  <td>{{class.level}}</td>
  <td>{{class.classNR}}</td>
  <td>{{getTeacherName(class.f_teacher)}}</td>
</tr>

https://plnkr.co/edit/gtu03gQHlRIMsh9vxr1c?p=preview

rob
  • 17,995
  • 12
  • 69
  • 94
  • Thank you! But now i get an [angular 10 $digest() iterations reached. aborting](http://stackoverflow.com/questions/17116114/how-to-troubleshoot-angular-10-digest-iterations-reached-error) error. I am not sure why it works in the plnkr, but not in my application. The custom filter is definitely the error cause. – JoCa Jul 05 '16 at 21:38
  • Nevermind, the plnkr javascript also throws an error. – JoCa Jul 05 '16 at 21:42