在$routeProvider中使用resolve会导致“Unknown provider ...”错误。

20
我尝试在我的应用程序加载之前执行异步http请求以加载一些数据,所以我在$routeProvider中使用一个resolve来进行$http请求。由于某种原因,我不断收到错误消息:Error: [$injector:unpr] Unknown provider: appDataProvider <- appData。其中appData是我执行http请求的地方。我正在使用AngularJS v1.2.5。

这里是代码和我尝试过的两种方法,它们都会产生相同的错误:

方法#1

MainController.js

var MainController = ['$scope','$location','appData',
    function($scope, $location, appData){
       console.log(appData.data);
    }
];

MainController.loadData = {
    appData: function($http, $location, MainFactory){
        var aid = MainFactory.extractAid($location);
        return $http({method: 'GET', url: URL_CONST + aid});
    }
};

app.js

var app = angular.module('HAY', ['ngRoute']);

app.config(function($routeProvider) {
  $routeProvider
    .when('/', {
      redirectTo: '/pages/alerts'
    })
    .when('/pages/:pageName', {
        templateUrl: function(params) {
            return 'views/pages/' + params.pageName + '.html';
        },
        controller: MainController,
        resolve: MainController.loadData
    })
    .otherwise({
        redirectTo: '/pages/alerts'
    });
});

我试图更改名称,以防它是系统保留关键字冲突,但没有成功。由于某种原因,appData从未被识别。

方法#2 我还尝试了这样的更改:

app.js

var app = angular.module('HEY', ['ngRoute']);

app.config(function($routeProvider) {
  $routeProvider
    .when('/', {
      redirectTo: '/pages/alerts'
    })
    .when('/pages/:pageName', {
        templateUrl: function(params) {
            return 'views/pages/' + params.pageName + '.html';
        },
        controller: MainController,
        resolve: {
                appData: ['$http', '$location','MainFactory', function($http, $location, MainFactory) {
                    var aid = MainFactory.extractAid($location);
                    return $http({method: 'GET', url: URL_CONST + aid});
                }]
        }
    })
    .otherwise({
        redirectTo: '/pages/alerts'
    });
});

MainController.js

var MainController = ['$scope','$location','appData',
    function($scope, $location, appData){
        console.log(resolvedData);
    }
];

然而,结果完全一样。这与Angular 1.2.5有关吗?

这是其他人的有效版本。

http://mhevery.github.io/angular-phonecat/app/#/phones

这是代码:

function PhoneListCtrl($scope, phones) {
  $scope.phones = phones;
  $scope.orderProp = 'age';
}

PhoneListCtrl.resolve = {
  phones: function(Phone) {
    return Phone.query();
  },
  delay: function($q, $defer) {
    var delay = $q.defer();
    $defer(delay.resolve, 1000);
    return delay.promise;
  }
}

angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
        when('/phones', {templateUrl: 'partials/phone-list.html', controller: PhoneListCtrl, resolve: PhoneListCtrl.resolve}).
        otherwise({redirectTo: '/phones'});
  }]);

1
我同意,在我的控制器中注入已解决的参数,效果非常好。 - m.e.conroy
2
@m.e.conroy,这个解决方案非常荒谬。请查看我发布的解决方案。希望能帮助到其他可能遇到同样问题的人。 - Georgi Angelov
1
@GeorgiAngelov,你指出的第二件事帮助我解决了问题。我完全忘记了我也将ng-controller设置为主体:)谢谢 - Jack Vo
2
@JackVo,我很高兴它有帮助!看起来这似乎不应该引起那么多问题 ;) - Georgi Angelov
1
解决方案点2帮助我使用AngularJS v1.3.2。 - Sam Vloeberghs
显示剩余9条评论
3个回答

2
以下是我在正在开发的应用程序中使用的代码示例,不确定它是否会有太大帮助,因为它与您已经拥有的方式并没有太大区别。
路由功能:
.when('/view/proposal/:id',{
    controller : 'viewProposalCtrl',
    templateURL : 'tmpls/get/proposal/view',
    resolve : viewProposalCtrl.resolveViewProposal
})

控制器

var viewProposalCtrl = angular.module('proposal.controllers')
    .controller('viewProposalCtrl',['$scope','contacts','details','rationale',
        function($scope,contacts,details,rationale){
            $scope.contacts = contacts;
            $scope.details = details;
            $scope.rationale = rationale;

            // [ REST OF CONTROLLER CODE ]
        });


// proposalSrv is a factory service

viewProposalCtrl.resolveViewProposal = {
    contacts : ['$route','proposalSrv',function($route,proposalSrv){
        return proposalSrv.get('Contacts',$route.current.params.id)
           .then(function(data){
               return data.data.contacts;
           },function(){
               return [];
           });
    }],
    details : ['$route','proposalSrv',function($route,proposalSrv){
        return proposalSrv.get('Details',$route.current.params.id)
            .then(function(data){
                return data.data.details;
            },function(){
                return {};
            });
    }],
    rationale : ['$route','proposalSrv',function($route,proposalSrv){
        return proposalSrv.get('Rationale',$route.current.params.id)
            .then(function(data){
                return data.data.rationale;
            },function(){
                return {};
            ]
    }]
};

现在想起来了,当我开发应用程序时,我曾经遇到过一个问题,不确定为什么当我将解决函数命名为“resolve”时,会出现问题:

.when('/path',{
     // stuff here
     resolve : myCtrlr.resolve
})

但这并没有:

.when('/path',{
     //stuff here
     resolve : myCtrlr.myResolveFn
})

另一种可能性

我能想到的唯一可能性是,你正在从$http调用中返回promise,然后尝试使用appData.data。请尝试使用.then函数或其他函数(.success,.error)从promise中获取信息。


谢谢您提供的示例。我的问题是,我甚至无法注入函数来实际使用then()或.success,.error)。我仍然无法弄清楚原因。我开始认为,angularjs 1.2.5与以前有所不同... - Georgi Angelov
这是一种可能性,自1.1.5以来发生了很多变化。也许你缺少一个模块或其他东西,可能类似于ngRoute的核心代码已经被拆分出去了。 - m.e.conroy
我刚刚发布了这个问题的解决方案。 - Georgi Angelov
这个设计存在一个问题,如果你使用 var controller = angular.module().controller() 来定义两个不同的控制器,那么这两个变量都会绑定到同一个对象上。因此,你不能有两个带有相同名称 resolveXX() 方法的控制器,否则只有最后一个控制器会在每个页面上被执行。 - El pocho la pantera
我从来没有遇到过按照我描述的方式做出问题,我编写了大规模应用程序,它们完全正常运行。 - m.e.conroy

1

问题不是由于之前使用了不同版本的AngularJS。

以下是使用我上面提供的代码修复的方法。

在app.js中,你需要将控制器声明为controller: 'MainController'而不是controller: MainController,尽管你已经有了var MainController = app.controller('MainController', ....)。

第二个也是最大的问题是,在我的index.html中,我已经声明了我的控制器,像这样:

index.html

这会导致整个“未知提供者”错误。显然,Angular不会告诉你已经声明了用于解析的控制器,而这将导致一个与解析无关的奇怪错误。

我希望这能帮助那些可能遇到同样问题的人。


0
在Angular 1.x文档中,我注意到的一件事是您不需要将已解析的参数指定为注释依赖项
因此,下面这个例子:
.when('/somewhere', {
  template: '<some-component></some-component>',
  resolve: {
    resolvedFromRouter: () => someService.fetch()
  }
})

export default [
  '$scope',
  'someService',
  'resolvedFromRouter'
  Controller
]

function Controller($scope, someService, resolvedFromRouter) {
  // <= unknown provider "resolvedFromRouter"
}

有误。在文档中,您没有将resolved参数指定为依赖项:

为了更轻松地从模板访问已解决的依赖项,解析映射将在路由的作用域下可用,位于$resolve(默认情况下)或由resolveAs属性指定的自定义名称下(请参见下文)。当使用组件作为路由模板时,这可能特别有用。

因此,请改为执行以下操作:

.when('/somewhere', {
  template: '<some-component></some-component>',
  resolve: {
    resolvedFromRouter: () => someService.fetch()
  }
})

export default [
  '$scope',
  'someService',
  Controller
]

function Controller($scope, someService) {
  $scope.$resolve.resolvedFromRouter; // <= injected here
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接