Error: $injector:unpr Unknown Provider, while calling service in controller in angular js

Issue

I am trying to use service in my controller and it is giving

Error: $injector:unpr
Unknown Provider
Unknown provider: getAuthorProvider <- getAuthor <- PostController

Here is what I am doing:

app.js

angular.module('app',[
    'ui.router',
    'app.controllers'
    ])
.config(['$stateProvider','$urlRouterProvider','$locationProvider',function($stateProvider,$urlRouterProvider,$locationProvider) {

    $stateProvider.state('homePage',{
        url: '/',
        views: {
            'mainView': {
                templateUrl: 'views/home.html',
                controller: 'PostController'
            }
        },      
    });
    $locationProvider.html5Mode(true);
    $urlRouterProvider.otherwise('/');
}]);

controller.js

angular.module('app.controllers',[
            'app.directives'
        ]).controller('PostController', ['$scope', '$http','getAuthor' , function($scope,$http,getAuthor) {
            $http({
                method: 'GET',
                url: '/api/blog'
            }).then(function (response){
                $scope.currentPage=1;
                $scope.pageSize=10;
                //console.log(response);
                $scope.posts = response.data;
                console.log($scope.posts);
                $scope.pageinput = $scope.currentPage;
                $scope.authorName = function(authorId) {
                    getAuthor.getAuthorNameById(authorId,function(response){
                        console.log(response.data);
                        //return response.data;
                    }, function(response){
                        alert('Some errors occurred while communicating with the service. Try again later.');
                    });
                };
                $scope.numberOfPages = function() {
                    return Math.ceil($scope.posts.length / $scope.pageSize);
                };
                $scope.setCurrentPage = function(newValue) {
                    $scope.currentPage = newValue;
                    $scope.pageinput = newValue;
                    $scope.$apply();
                };
                $scope.submitFunc = function() {
                    var temp = $scope.currentPage;
                    if($scope.pageinput >=0 && $scope.pageinput <= $scope.numberOfPages()) {
                        $scope.currentPage = $scope.pageinput;
                        $scope.CurrentPage = $scope.currentPage;
                        setTimeout(window.scrollTo(0,150),2000);
                    }else {

                    }
                }
            },function(error){
                console.log('failed');
            });
        }]);

service.js

angular.module('app.factories',[
    'LocalStorageModule'
    ]).factory('getAuthor',['Restangular',function(Restangular) {
    function getAuthorNameById(authorId,onSuccess,onError) {
        Restangular.one('api/author/name',authorId).get().then(function(response){
            onSuccess(response);
        }, function(response) {
            onError(response);
        });
    }
}]);

I am calling the function authorName() in my HTML file as:

{{authorName(2)}}

as this function should take authorId and return his name. I am not sure where I am getting it wrong and now I am not getting any idea how to set it perfectly.

Solution

it seems you did not include app.factories as a dependency as reported by @charlietfl

in addition you’re missing the return statement inside the factory, you’re only declaring the function, this could be related to the error.

angular.module('app.factories',[
    'LocalStorageModule'
    ]).factory('getAuthor',['Restangular',function(Restangular) {
    function getAuthorNameById(authorId,onSuccess,onError) {
      Restangular.one('api/author/name',authorId).get().then(function(response){
            onSuccess(response);
        }, function(response) {
            onError(response);
        });
    }

    return {
     getAuthorNameById: getAuthorNameById
    }
}]);

And move the invocation of authorName() inside your controller.
When you interpolate a function call (as you did in your template, with this syntax {{authorName(2)}}) the function will be called each digest cycle.

To answer your question in the comments i’d follow this approach.

.directive('handleItem', function(getAuthor){
  return {
   restrict: 'E',
   scope: {
    item: '='
   }
   link: function(scope, elem, attrs){
     //make the call here 
     getAuthor
     .getAuthorNameById($scope.item.authorId,function(response){
        console.log(response.data);
        //return response.data;
     }, function(response){
        alert('Some errors occurred while communicating with the service. 
         Try again later.');
     });
   }
  }
})

and in the template something like this:

<div ng-repeat="item in items"> <!--loop over your items-->
  <handle-item item="item"></handle-item>
</div>

Answered By – Karim

Answer Checked By – Marie Seifert (AngularFixing Admin)

Leave a Reply

Your email address will not be published.