0

I have an app where I am using ngRoute to generate an SPA. I don't want to load the view until I have finished fetching the data from the DB. The below works but I am unable to pass the return data to my controller.

Angular Service:

angular.module('routeService',[])

.factory('dataFetch', function($http, $q){

var deferred = $q.defer();
var factory = {}

factory.getProposals = function(){


    return $http.get('urlHere')
        .then(function(response){
            //promise is fulfilled
            deferred.resolve(response.data);

            console.log("readched the bio service!" + response.data);

            //promise is returned
           // return deferred.promise;
            return response.data;

        }, function(response){
            deferred.reject(response);

            //promise is returned
            return deferred.promise;
        });};


      return factory;

   });

Angular Controller:

var login = angular.module('login', ['ngRoute', 'routeService'])

 // configure our routes
login.config(function($routeProvider,$locationProvider) {
    $routeProvider

        // route for the home page

        .when('/', {
            templateUrl: '/overview.html',
            controller: 'login',
            resolve: {
                myDta: function(dataFetch){
                    return dataFetch.getProposals();
                }
            }

        })

});

login.controller('login', function($scope, myDta){

   $scope.prop = myDta

}) 

I get the following error:

Unknown provider: myDtaProvider <- myDta <- login

Skywalker
  • 4,984
  • 16
  • 57
  • 122

2 Answers2

0

Erroneous Use of ng-controller='login'

I get the following error:

Unknown provider: myDtaProvider <- myDta <- login

The error message means that the login controller is being instantiated from an ng-controller directive somewhere. When the ngRoute services instantiates a controller, it will inject resolves as a local. The ng-controller directive does not have access to the resolves from a router.

From another StackOverflow Answer:1

ngRoute supports injection of resolved variables to the controller, which is useful for cross-cutting concerns of the app, like authentication or configuration of the app.

The downside is that the controller can only be instantiated with these parameters available to be injected, which means that either you instantiate your controller manually (with $controller), which almost never the case, or with ngRoute with resolve. What you cannot do with such a controller is instantiate it with ng-controller or in any other location where the injected parameters are not available.

This error indicates that in addition to having defined the controller on the route, you also have the controller defined as ng-controller in the template of the route. This second instantiation of the controller is what fails.

-- StackOver: How to inject dependency from resolve routeProvider


Deferred Anti-Pattern2

The dataFetch service erroneously implements a classic deferred anti-pattern. The $http service already returns a promise. There is no need to manufacture a promise with $q.defer(). Instead chain and return from the $http promise.

angular.module('routeService',[])

.factory('dataFetch', function($http, $q){

    //var deferred = $q.defer();
    var factory = {}
    
    factory.getProposals = function(){

        return $http.get('urlHere')
            .then(function onSuccess(response){    
                console.log("readched the bio service!" + response.data);
                //return to chain data
                return response.data;
    
            }, function onReject(errorResponse){
                //throw to chain rejection
                throw errorResponse;
            });
    };

    return factory;

});

For more information, see StackOverflow: Is this a “Deferred Antipattern”?

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
-2

You can use $route service to access resolved values as explained here. Further your factory has very annoying things. You are using a global promise and returning promise in case of error. That is totally wrong. Correct way to use promise is

angular.module('routeService',[])
   .factory('dataFetch', function($http, $q) {
       var factory = {}
       factory.getProposals = function() {

          var deferred = $q.defer();
          $http.get('urlHere')
             .then(function(response) {
                 // Do what else you want to do
                 deferred.resolve(response.data);
             }, function(response) {
                 // Do what else you want to do
                 deferred.reject(response);
             });

          return deferred.promise;
       };

       return factory;
   });

And add dependency to resolve data in routes like this

 $routeProvider

    // route for the home page

    .when('/', {
        templateUrl: '/overview.html',
        controller: 'login',
        resolve: {
            myDta: function(dataFetch){
                return dataFetch.getProposals();
            }
        }

    })

You can access myDep in login controller as followed:

 login.controller('login', function($scope, $route) {
    $scope.myDta = $route.current.locals.myDta;
 });

Here is the working example: http://plnkr.co/edit/WSJk8dhXv1Fvv4yaGf5n?p=preview

Community
  • 1
  • 1
Adnan Umer
  • 3,669
  • 2
  • 18
  • 38