Search code examples
angularjsrestangular

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


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>