7

I created this filter to transform userID to user's name:

angular.module('idToName', ['userService'])

.filter('idToName', function(User) {
  User.allUsers()
  .success(function(data) {
    userData = data;
  });
  var assignee;
  return function(IDs) {
    for (var j = 0; j < userData.length; i++) {
      for (var i = 0; i < IDs.length; j++){
        if (IDs[i] == userData[j]._id) {
          assignee[i] = userData[j].firstname + ' ' + userData[j].lastname + ' ' + userData[j].cname;
        }
      }
    }
    return assignee;
  }
})

It takes in an array of userIDs, and it should find the corresponding userData object and return its names.

But when I run it, it gets this error:

Error: $injector:unpr
Unknown Provider

Unknown provider: idToNameFilterProvider

So what did I do wrong? I would appreciate any help.

Joy
  • 9,430
  • 11
  • 44
  • 95
thousight
  • 1,134
  • 1
  • 14
  • 39
  • 2
    How do you use `idToName`? – Joy Aug 13 '15 at 00:40
  • 2
    Your `userData` is obtained asyncly, when you call the filter, the `userData` may not have arrived yet. – Joy Aug 13 '15 at 00:42
  • Separate issue. If the IDs are what you are searching for, then IDs should be the outer loop and userData the inner loop. Then put a break inside the if statement so you don't continue to look for a match after you find it. – Mike Aug 13 '15 at 00:59
  • 4
    The error is coming from the code that is trying to use the filter, not the filter itself. Either the Javascript file with the filter in it is not loaded (or if using AMD, the module isn't being required), or the `idToName` module isn't listed as a dependency. – ach Aug 13 '15 at 01:11
  • 2
    filter needs to be synchronous. Use arguments to pass in data that will be received later then just check if that argument is defined or not – charlietfl Aug 13 '15 at 01:29
  • @Joy I just use it on the html where I list the user's ID. Basically {{eachUser._id | idToName}} – thousight Aug 13 '15 at 01:53
  • @Joy How should I change it to make it run synchronously then? – thousight Aug 13 '15 at 01:55
  • @ach is most likely correct concerning the question as asked. The other suggestions will fix a problem that will appear once you have properly included the file and injected the code. – tuckerjt07 Aug 13 '15 at 02:33

1 Answers1

3

Please check working demo: JSFiddle

angular.module('idToName', [])
    .factory('userService', ['$http', function ($http) {
    var users = [];
    return {
        all: function () {
            return $http.get('http://jsonplaceholder.typicode.com/users');
        }
    };
}])
    .filter('idToName', function () {
    var assignee = [];
    return function (userData, IDs) {
        if (!userData || userData.length === 0) {
            return 'loading...';
        }
        for (var i = 0; i < userData.length; i++) {
            for (var j = 0; j < IDs.length; j++) {
                if (IDs[j] == userData[i].id) {
                    assignee[i] = userData[i].name + ' ' + userData[i].username + ' ';
                }
            }
        }
        return assignee;
    }
})
    .controller('MyCtrl', ['$scope', 'userService', function ($scope, userService) {
    $scope.IDs = [1, 2, 3, 4];
    $scope.users = [];
    userService.all().success(function (data) {
        $scope.users = data;
    });
}]);

Use it in HTML:

<div ng-app="idToName" ng-controller='MyCtrl'>{{ users | idToName:IDs }}</div>

Some issues in your code:

  1. Your userData is obtained asyncly, when you call the filter, the userData may not have arrived yet. And your filter should not be fetching data. Because it is not its job. You'd better separate the data-fetching logic to some independent logic. So I created another service userService

  2. You nested for loop is messed with the i and j variables. I have made them working.

  3. idToName is not a good module name.


Update 1

Learned from comments of @tuckerjt07 and @ach, please check your JavaScript inclusion and module dependency code. There must be something wrong when trying to inject the filter. Seems the filter itself is not found within the context.

Joy
  • 9,430
  • 11
  • 44
  • 95
  • While valid it doesn't address the issue as represented in the question. The asynchronous call wouldn't throw an injector error. – tuckerjt07 Aug 13 '15 at 02:34
  • @tuckerjt07 I tried to clear out the problem regarding mixing async calls and filters. Em, there must be something wrong when calling the filter, which causes the injector error. But we don't have the full picture. That might be solved upon question owners' investigation into his/her code. – Joy Aug 13 '15 at 02:40
  • the error he gave us matches perfectly with what ach suggested to fix it. – tuckerjt07 Aug 13 '15 at 02:43
  • Wow thanks for the help guys. I've tried the method @Joy and @ ach suggested. I fixed the issue @ ach mentioned, that was indeed a silly mistake. But as for your jsFiddle, it seems that the filter isn't even used or working cuz your html is just showing users rather than ID – thousight Aug 13 '15 at 04:33
  • @thousight Here `{{ users | idToName:IDs }}` calls the filter to work. The `$http` call gets the `user` objects only. – Joy Aug 13 '15 at 05:15
  • @Joy But what I need is actually {{ _id | idToName: IDs }} cuz I need to transfer my IDs to its corresponding name. Also, I don't get how you put 2 params into the filter, cuz when I try it on my code, it could only take the first param. Sorry I'm newbie – thousight Aug 13 '15 at 05:53
  • Also isn't {{ users | idToName:IDs }} calling $scope.users instead of $scope.IDs? – thousight Aug 13 '15 at 05:58
  • @thousight for multiple arguments to a filter, check [How do I call an Angular.js filter with multiple arguments?](http://stackoverflow.com/questions/16227325/how-do-i-call-an-angular-js-filter-with-multiple-arguments). In the JSFiddle, I use `IDs` as the argument. Of course you can switch the `users` and `IDs` ([JSFiddle](http://jsfiddle.net/bbyj308h/2/)). I don't know what `_id` is in your comment. – Joy Aug 13 '15 at 06:56
  • That was actually $scope.IDs on your JSFiddle – thousight Aug 13 '15 at 07:34
  • I think my last comment gives what you want. This question can be closed. – Joy Aug 13 '15 at 07:41