繁体   English   中英

将Promise传递给Angular-UI状态控制器

[英]Pass a promise into an Angular-UI state controller

是否可以从外部控制器(例如触发状态的控制器)向UI.Router $state传递承诺?

我知道$state.go()返回一个承诺; 是否可以 使用您自己的承诺 覆盖它, 直接自己解决此承诺还是使用新的承诺来解决?

此外,文档还说$state.go()返回的$state.go()可以被另一个promise拒绝(由transition superseded ),但是我找不到任何地方可以指示如何在州内完成此操作。

例如,在下面的代码中,我希望能够在继续执行doSomethingElse()之前等待用户单击按钮( $scope.buttonClicked() doSomethingElse()

我知道我可以发出一个事件,但是由于将Promise深深地嵌入到Angular中,所以我想知道是否有一种方法可以通过promise.resolve / promise.reject

angular.module('APP', ['ui.router'])
.config(['$stateProvider', function ($stateProvider) {
    $stateProvider
    .state('myState', {
        template: '<p>myState</p>',
        controller: ['$state', '$scope', '$q', function ($state, $scope, $q) {
            var deferred = $q.defer();

            $scope.buttonClicked = function () {
                deferred.resolve();
            }
        }]
    });
}])
.controller('mainCtrl', ['$state', function ($state) {
    $state.go('myState')
    .then(doSomethingElse)
}]);

更新我接受了@blint的回答,因为它使我离想要的东西最近。 下面是一些代码,这些代码进一步完善了这个答案的想法。 我认为我写这本书的方式不是一个非常优雅的解决方案,如果有人可以提出一种更好的方法来解决来自触发状态的承诺,我感到很高兴。

我选择的解决方案是像平常在控制器中那样链接您的诺言,但是将$scope.next()方法(或类似方法)附加到解析/拒绝诺言的该作用域。 由于状态可以继承调用控制器的作用域,所以它将能够直接调用该方法,从而解决/拒绝承诺。 这是可能的工作方式:

首先,使用调用$scope.next()方法的按钮/控制器来设置状态:

.config(function ($stateProvider) {
    $stateProvider
    .state('selectLanguage', {
        template: '<p>Select language for app: \
            <select ng-model="user.language" ng-options="language.label for language in languages">\
                <option value="">Please select</option>\
            </select>\
            <button ng-click="next()">Next</button>\
            </p>',
        controller: function ($scope) {
            $scope.languages = [
                {label: 'Deutch', value: 'de'},
                {label: 'English', value: 'en'},
                {label: 'Français', value: 'fr'},
                {label: 'Error', value: null}
            ];
        }
    })
    .state('getUserInfo', {
        template: '<p>Name: <input ng-model="user.name" /><br />\
            Email: <input ng-model="user.email" /><br />\
            <button ng-click="next()">Next</button>\
            </p>'
    })
    .state('mainMenu', {
        template: '<p>The main menu for {{user.name}} is in {{user.language.label}}</p>'
    })
    .state('error', {
        template: '<p>There was an error</p>'
    });
})

接下来,设置控制器。 在这种情况下,我使用的是本地服务方法user.loadFromLocalStorage()使球滚动(它返回一个user.loadFromLocalStorage() ),但是任何user.loadFromLocalStorage()都可以。 在此工作流程中,如果$scope.user缺少任何内容,它将使用状态逐渐填充它。 如果已完全填充,它将直接跳到主菜单。 如果元素保留为空或处于无效状态,则会进入错误视图。

.controller('mainCtrl', function ($scope, $state, $q, User) {
    $scope.user = new User();

    $scope.user.loadFromLocalStorage()
    .then(function () {
        var deferred;

        if ($scope.user.language === null) {
             deferred = $q.defer();

             $state.go('selectLanguage');

             $scope.next = function () {
                $scope.next = undefined;

                if ($scope.user.language === null) {
                    return deferred.reject('Language not selected somehow');
                }

                deferred.resolve();
             };

             return deferred.promise;
        }
    })
    .then(function () {
        var deferred;

        if ($scope.user.name === null || $scope.user.email === null) {
            deferred = $q.defer();

            $state.go('getUserInfo');
            $scope.next = function () {
                $scope.next = undefined;

                if ($scope.user.name === null || $scope.user.email === null) {
                    return deferred.reject('Could not get user name or email');
                }

                deferred.resolve();
            };

            return deferred.promise;
        }


    })
    .then(function () {
        $state.go('mainMenu');
    })
    .catch(function (err) {
        $state.go('error', err);
    });

});

这很冗长,但还不是很干燥,但是它显示了使用promises进行异步流控制的总体意图。

承诺的目的是保证结果...或处理失败。 可以将承诺链接起来,在函数中返回,然后进行扩展。

您对“超越”承诺毫无兴趣。 但是,您可以做什么:

  • 处理故障案例。 这是文档中的示例:
 promiseB = promiseA.then(function(result) { // success: do something and resolve promiseB // with the old or a new result return result; }, function(reason) { // error: handle the error if possible and // resolve promiseB with newPromiseOrValue, // otherwise forward the rejection to promiseB if (canHandle(reason)) { // handle the error and recover return newPromiseOrValue; } return $q.reject(reason); }); 
  • 在promise链中追加一个新的异步操作。 您可以结合承诺。 如果链中调用的方法返回了一个Promise,则当新的Promise被解决后,父Promise将在链的其余部分进行填充。

这是您可能正在寻找的模式:

angular.module('APP', ['ui.router'])
.config(['$stateProvider', function ($stateProvider) {
    $stateProvider
    .state('myState', {
        template: '<p>myState</p>',
        controller: 'myCtrl'
    });
}])
.controller('myCtrl', ['$scope', '$state', '$q', '$http', 'someAsyncServiceWithCallback',
    function ($scope, $state, $q, $http, myService) {
    $scope.buttonClicked = function () {
        $state.go('myState')
        .then(function () {
            // You can return a promise...
            // From a method that returns a promise
            // return $http.get('/myURL');

            // Or from an old-school method taking a callback:
            var deferred = $q.defer();
            myService(function(data) {
                deferred.resolve(data);
            });

            return deferred.promise;
        },
        function () {
            console.log("$state.go() failed :(");
        });
    };
}]);

也许实现这一目标的一种方法是从国家resolve恢复您的诺言

resolve: {
    myResolve: function($scope, $q) {
        var deferred = $q.defer();
        $scope.buttonClicked = function () {
           deferred.resolve();
        }
        return deferred.promise;
    }
}

解析文档中还有一个示例可能会引起您的兴趣

 // Another promise example. If you need to do some 
 // processing of the result, use .then, and your 
 // promise is chained in for free. This is another
 // typical use case of resolve.
 promiseObj2:  function($http){
    return $http({method: 'GET', url: '/someUrl'})
       .then (function (data) {
           return doSomeStuffFirst(data);
       });
 },

暂无
暂无

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

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