繁体   English   中英

Angular:在控制器中设置返回值之前,如何等待服务中的承诺得到解决?

[英]Angular: How can I wait for a promise in a service to be resolved before I set the returned value in my controller?

我正在使用angular并提供以下服务:

myApp.factory('MyService', ['$http', function ($http) {
    return {
        getData: function (ID) {
            var promise = $http.get('Holdings/GetGridData?Id=' + ID)
            .then(function (response) {
                return response.data;
            });
            return promise;
   }};
}]);

然后我在控制器中使用以下命令调用它:

function createData(ID) {
    MyService.getData(ID).then(function (data) {
        $scope.JsonData = data;
    });

    return $scope.JsonData;
};

但是,首次启动CreateData时,它返回未定义,返回后,在控制台中可以看到显示:XHR加载完成:GET“ http:// localhost:50243 / Holdings / GetGridData?Id = 2 ”。

因此,它可以正确读取数据,但是在我将$ scope.JsonData设置为undefined之后。 此后,当我再次触发该事件时,但是$ scope.JsonData正确设置为数据。 我的问题是,在第一次触发事件时,如何让控制器在设置值之前等待服务中的诺言得到解决?

恐怕这是不可能的。 您为什么不喜欢控制器中的promise方法?

第一次调用该函数将返回undefined。 同时,promise被解决,在作用域上设置值,这将触发$ digest循环。

您将在对一个请求的承诺之前返回response.data,并且实际上并没有从服务中返回http请求本身。

另外,您无需在控制器中返回任何内容。 完成此操作的最简单方法是从服务返回$ http请求并在控制器中处理响应。

示例: https//jsfiddle.net/bmopcr97/

function AppCtrl($scope, Service) {
  var ID = 123;
  Service.getData(ID).then(function(response) {
    $scope.JsonData = response.data;
  });
}

function Service($http) {
  return {
    getData: function(ID) {
      return $http.get('Holdings/GetGridData?Id=' + ID);
    }
  }
}

解决此问题的一种好方法是通过路由器的解析器。 这是在angular的默认路由器中使用解析器的示例(如果使用ui-router,则有所不同,但是概念是相同的)。

$routeProvider
    .when("/news", {
        templateUrl: "newsView.html",
        controller: "newsController",
        resolve: {
            message: function(messageService){
                return messageService.getMessage();
        }
    }
});

在这里, messageService.getMessage()返回一个promise(类似于您的示例函数getData() )。 如果您随后将message作为参数包含在控制器中,则控制器将在执行之前等待promise被解决。

You need to defer, resolve and return your promises in a 'Factory' or 'Services' file. 
Then make a call to the respective method in the Factory file in your 'Controller' file. 
Factories and Controllers perform totally different functions. All your API calls will
have to be your 'Factory' file and then you can manipulate your data in your 
'Controller'

Refer to example below :

//------------------------------------------------------------------------------------
# user.factory.js
# 'app.foo.user' refers to your directory structure i.e. app/foo/user/user.factory.js

(function() {
    'use strict';

    angular
        .module('app.foo.user', [])
        .factory('userSvc', UserService);

    /* @ngInject */
    function UserService(
        $log,
        $q,
        $http,
        $window,
        $state,
        logger,
        session,
        utils,
        API_CONFIG) {

        var ENDPOINTS = {
            USERS: '/v1/users'
        };

        /**
         * @ngdoc service
         * @name app.foo.user
         * @description User management
         */
        var service = {
            get: get
        };

        /**
         * @ngdoc method
         * @name get
         * @description Returns all users
         * @methodOf app.foo.user
         * @returms {promise} user or null if not found
         */
        function get() {
            var q = $q.defer();

            var request = utils.buildAuthRequest( session, 'GET', ENDPOINTS.USERS );

            $http(request)
              .success(function (users) {
                  q.resolve(users.result);
              })
              .error(function (error) {
                  logger.error('UserService.get > Error ', error);

            return q.promise;
        }
    }
})();

//------------------------------------------------------------------------------------
# user.module.js
# 'app.foo.user' refers to your directory structure i.e. app/foo/user/user.module.js

(function() {
    'use strict';

    angular
        .module('app.foo.user', [
        ]);
})();

//------------------------------------------------------------------------------------
# user-list.controller.js
# This is where you make a call to the 'get' method in the 'user.factory.js' where the promises 
# were defered, resolved and returned.
# And you gave to inject 'userSvc' in this file so as to connect to the 'user.factory.js' file.
# 'app.foo.admin' refers to your directory structure i.e. app/foo/admin/user-list.controller.js

 (function() {
    'use strict';

    angular
        .module('app.foo.admin')
        .controller('UsersListController', UsersListController);

    /* @ngInject */

    function UsersListController(
        $scope,
        $state,
        $timeout,
        $log,
        userSvc) {
        var vm = this;
        vm.loading = false;
        vm.userSvc = userSvc;

        activate();

        function activate() {
            // init users
            vm.userSvc.get().then(
                function(users) {
                    vm.users = users;
                },
                function(error) {
                    $log.error(error);
                }
            );
        }
    }
})();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM