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

时间:2021-07-13 20:56:48

I'm using angular and have the following service:

我正在使用角度,并提供以下服务:

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;
   }};
}]);

and then I call that in my controller using:

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

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

    return $scope.JsonData;
};

However, when CreateData is first fired it returns undefined, and after this is returned, I can see in the console I can see it display: XHR finished loading: GET "http://localhost:50243/Holdings/GetGridData?Id=2".

但是,当第一次触发CreateData时它返回undefined,在返回之后,我可以在控制台中看到我可以看到它显示:XHR完成加载:GET“http:// localhost:50243 / Holdings / GetGridData?Id = 2 ”。

So, it correctly reads the data, but after my $scope.JsonData is set to undefined. After this, when I fire the event again, $scope.JsonData is correctly set to the data, however. My question is, on the first time the event is fired, how can I make the controller wait for the promise in the service to be resolved before setting the value?

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

4 个解决方案

#1


0  

I'm afraid this isn't possible. Why don't you like the promise approach in controller?

我担心这是不可能的。你为什么不喜欢控制器中的承诺方法?

First call of the function will return undefined. Meanwhile, promise is resolved, value is set on the scope and this triggers $digest cycle.

首次调用该函数将返回undefined。同时,承诺得到解决,在范围上设置值,这会触发$ digest循环。

#2


0  

You're returning the response.data before the promise for one, and you're not actually returning the http request itself from the service.

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

Also, you don't need to return anything in your controller. The simplest way to accomplish this is just returning your $http request from the service and handling the response in your controller.

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

Example: 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);
    }
  }
}

#3


0  

A great way to handle this is through your router's resolvers. Here's an example of using a resolver in angular's default router (it's a little different if you use ui-router, but the concept is the same).

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

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

Here, messageService.getMessage() returns a promise (similar to your example function getData()). If you then include message as an argument in your controller, the controller will wait for the promise to be resolved before executing.

这里,messageService.getMessage()返回一个promise(类似于你的示例函数getData())。如果然后在控制器中包含消息作为参数,则控制器将在执行前等待承诺解析。

#4


0  

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);
                }
            );
        }
    }
})();

#1


0  

I'm afraid this isn't possible. Why don't you like the promise approach in controller?

我担心这是不可能的。你为什么不喜欢控制器中的承诺方法?

First call of the function will return undefined. Meanwhile, promise is resolved, value is set on the scope and this triggers $digest cycle.

首次调用该函数将返回undefined。同时,承诺得到解决,在范围上设置值,这会触发$ digest循环。

#2


0  

You're returning the response.data before the promise for one, and you're not actually returning the http request itself from the service.

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

Also, you don't need to return anything in your controller. The simplest way to accomplish this is just returning your $http request from the service and handling the response in your controller.

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

Example: 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);
    }
  }
}

#3


0  

A great way to handle this is through your router's resolvers. Here's an example of using a resolver in angular's default router (it's a little different if you use ui-router, but the concept is the same).

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

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

Here, messageService.getMessage() returns a promise (similar to your example function getData()). If you then include message as an argument in your controller, the controller will wait for the promise to be resolved before executing.

这里,messageService.getMessage()返回一个promise(类似于你的示例函数getData())。如果然后在控制器中包含消息作为参数,则控制器将在执行前等待承诺解析。

#4


0  

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);
                }
            );
        }
    }
})();