È possibile passare una promessa a un UI.Router $state
da un controller esterno (ad esempio, il controller che ha attivato lo stato)?Passa una promessa in un controller di stato Angular-UI
So che $state.go()
restituisce una promessa; è possibile
ignorare che con la propria promessa
risolvere direttamente questa promessa o risolverlo con una nuova promessa?
Inoltre, la documentazione dice il promessa restituito da $state.go()
può essere respinta con un'altra promessa (indicato da transition superseded
), ma non riesco a trovare da nessuna parte che indica come questo può essere fatto all'interno dello Stato stesso.
Ad esempio, nel codice seguente, vorrei poter aspettare che l'utente faccia clic su un pulsante ($scope.buttonClicked()
) prima di continuare su doSomethingElse()
.
So che posso emettere un evento, ma dal momento che le promesse sono infuse in Angular così profondamente, mi sono chiesto se c'era un modo per farlo attraverso 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)
}]);
Aggiornamento ho accettato la risposta di @ BLINT come mi vicina ha avuto modo di quello che volevo. Di seguito è riportato un codice che arricchisce l'idea di questa risposta un po 'di più. Non penso che il modo in cui ho scritto questa sia una soluzione molto elegante e sono felice che qualcuno possa suggerire un modo migliore per risolvere le promesse da uno stato innescato.
La soluzione che ho scelto è quello della catena tue promesse come si farebbe normalmente nel controller, ma lasciare un $scope.next()
metodo (o qualcosa di simile) collegato a tale ambito che risolve/respinge la promessa. Poiché lo stato può ereditare l'ambito del controller chiamante, sarà in grado di invocare direttamente quel metodo e quindi risolvere/rifiutare la promessa. Ecco come potrebbe funzionare:
In primo luogo, impostare il tuo Stati con pulsanti/controller che richiedono un metodo $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>'
});
})
Successivamente, è istituito il controller. In questo caso, sto usando un metodo di servizio locale, user.loadFromLocalStorage()
per far rotolare la palla (restituisce una promessa), ma qualsiasi promessa lo farà. In questo flusso di lavoro, se lo $scope.user
manca qualcosa, verrà progressivamente popolato utilizzando gli stati. Se è completamente popolato, salta direttamente al menu principale. Se gli elementi vengono lasciati vuoti o si trovano in uno stato non valido, viene visualizzata una vista di errore.
.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);
});
});
questo è abbastanza verbose e non ancora molto secco, ma dimostra l'intenzione generale di controllo del flusso asincrono mediante promesse.
Cosa intendi con 'è possibile scavalcarlo con la tua stessa promessa?'? – blint
Siamo spiacenti. Immagino che il modo migliore per dire che sia, puoi risolvere una promessa "$ stato" con la tua stessa promessa. – Andrew