![](/img/trans.png)
[英]Angular-UI Router - Resolve not waiting for promise to resolve due state switching
[英]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); });
这是您可能正在寻找的模式:
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.