A propriedade $ routeProvider resolve permite atrasar a alteração de rota até que os dados sejam carregados.
Primeiro defina uma rota com resolve
atributo como este.
angular.module('phonecat', ['phonecatFilters', 'phonecatServices', 'phonecatDirectives']).
config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/phones', {
templateUrl: 'partials/phone-list.html',
controller: PhoneListCtrl,
resolve: PhoneListCtrl.resolve}).
when('/phones/:phoneId', {
templateUrl: 'partials/phone-detail.html',
controller: PhoneDetailCtrl,
resolve: PhoneDetailCtrl.resolve}).
otherwise({redirectTo: '/phones'});
}]);
observe que a resolve
propriedade está definida na rota.
function PhoneListCtrl($scope, phones) {
$scope.phones = phones;
$scope.orderProp = 'age';
}
PhoneListCtrl.resolve = {
phones: function(Phone, $q) {
// see: https://groups.google.com/forum/?fromgroups=#!topic/angular/DGf7yyD4Oc4
var deferred = $q.defer();
Phone.query(function(successData) {
deferred.resolve(successData);
}, function(errorData) {
deferred.reject(); // you could optionally pass error data here
});
return deferred.promise;
},
delay: function($q, $defer) {
var delay = $q.defer();
$defer(delay.resolve, 1000);
return delay.promise;
}
}
Observe que a definição do controlador contém um objeto de resolução que declara itens que devem estar disponíveis para o construtor do controlador. Aqui o phones
é injetado no controlador e é definido na resolve
propriedade
A resolve.phones
função é responsável por retornar uma promessa. Todas as promessas são coletadas e a alteração da rota é adiada até que todas as promessas sejam resolvidas.
Demonstração de trabalho: http://mhevery.github.com/angular-phonecat/app/#/phones
Fonte: https://github.com/mhevery/angular-phonecat/commit/ba33d3ec2d01b70eb5d3d531619bf90153496831
angular.controller()
definições de controlador de tipo? No$routeProvider
material, pensei que você tivesse que usar nomes de string de controladores.angular.controller()
, pode atribuir o resultado desta função a uma variável (var MyCtrl = angular.controller(...)
) e depois trabalhar com isso (MyCtrl.loadData = function(){..}
). Veja o vídeo de egghead, o código é mostrado lá imediatamente: egghead.io/video/0uvAseNXDr0Aqui está um exemplo de trabalho mínimo que funciona para o Angular 1.0.2
Modelo:
JavaScript:
http://jsfiddle.net/dTJ9N/3/
Versão simplificada:
Como $ http () já retorna uma promessa (também adiada), na verdade não precisamos criar nossa própria. Para que possamos simplificar o MyCtrl. resolver para:
O resultado de $ http () contém dados , status , cabeçalhos e objetos de configuração , portanto, precisamos alterar o corpo do MyCtrl para:
http://jsfiddle.net/dTJ9N/5/
fonte
Unknown provider: datasetsProvider <- datasets
function($http) { return $http({method: 'GET', url: '/someUrl'}) .then( function(data){ return data;}, function(reason){return 'error value';} ); }
Vejo algumas pessoas perguntando como fazer isso usando o método angular.controller com injeção de dependência amigável à minificação. Desde que acabei de trabalhar, senti-me obrigado a voltar e ajudar. Aqui está minha solução (adotada da pergunta original e da resposta de Misko):
Como esse código é derivado da pergunta / resposta mais popular, ele não foi testado, mas deve ser enviado na direção certa, se você já entender como tornar um código angular amigável à minificação. A parte que o meu próprio código não exige foi a injeção de "Phone" na função de resolução para 'phones', nem usei nenhum objeto 'delay'.
Eu também recomendo este vídeo do YouTube http://www.youtube.com/watch?v=P6KITGRQujQ&list=UUKW92i7iQFuNILqQOUOCrFw&index=4&feature=plcp , o que me ajudou um pouco
Se lhe interessar, decidi também colar meu próprio código (escrito em coffeescript) para que você possa ver como eu o fiz funcionar.
Para sua informação, com antecedência eu uso um controlador genérico que me ajuda a fazer CRUD em vários modelos:
fonte
resolve
função no controlador, nas versões recentes do Angular? Portanto, ele deve ser declarado na configuração, como está aqui?$defer
serviço indefinido , observe que na versão 1.5.7 do AngularJS, você deseja usar$timeout
.Esse commit , que faz parte da versão 1.1.5 e posterior, expõe o
$promise
objeto de$resource
. Versões do ngResource, incluindo esta confirmação, permitem resolver recursos como este:$ routeProvider
controlador
fonte
GET '/api/1/apps/:appId'
->App.get({id: $routeParams.appId}).$promise();
eu não posso usar assim #$route
sua resolução e uso$route.current.params
. Cuidado,$routeParams
ainda está apontando para a rota antiga.Esse snippet é compatível com injeção de dependência (eu até o uso em combinação de ngmin e uglify ) e é mais elegante solução baseada em domínio .
O exemplo abaixo registra um recurso Phone e um phoneRoutes constante , que contém todas as suas informações de roteamento para esse domínio (telefone). Algo que não gostei na resposta fornecida foi a localização da lógica de resolução - o módulo principal não deve saber nada ou se preocupar com a maneira como os argumentos dos recursos são fornecidos ao controlador. Dessa forma, a lógica permanece no mesmo domínio.
Nota: se você estiver usando ngmin (e se não estiver: deve) deve escrever apenas as funções de resolução com a convenção de matriz DI.
A próxima parte é injetar os dados de roteamento quando o módulo estiver no estado de configuração e aplicá-los ao $ routeProvider .
Testar a configuração da rota com esta configuração também é bastante fácil:
Você pode vê-lo com toda a glória no meu mais recente experimento . Embora esse método funcione bem para mim, eu realmente me pergunto por que o injetor $ não está atrasando a construção de nada quando detecta a injeção de qualquer coisa que seja um objeto de promessa ; isso tornaria as coisas muuuuito mais fáceis.
Edit: usado Angular v1.2 (rc2)
fonte
I really wonder why the $injector isn't delaying construction of anything when it detects injection of anything that is a promise object
Suponho que eles tenham omitido essa funcionalidade porque isso pode incentivar padrões de design que afetam negativamente a capacidade de resposta dos aplicativos. O aplicativo ideal em sua mente é verdadeiramente assíncrono, portanto, a resolução deve ser um caso de extrema importância.O atraso na exibição da rota certamente levará a um emaranhado assíncrono ... por que não simplesmente rastrear o status de carregamento da sua entidade principal e usá-lo na exibição. Por exemplo, no seu controlador, você pode usar os retornos de sucesso e erro no ngResource:
Então, na visualização, você pode fazer o que for:
fonte
Eu trabalhei com o código de Misko acima e foi isso que fiz com ele. Esta é uma solução mais atual, pois
$defer
foi alterada para$timeout
. Substituir,$timeout
no entanto, aguardará o período de tempo limite (no código de Misko, 1 segundo) e retornará os dados esperando que sejam resolvidos a tempo. Dessa forma, ele retorna o mais rápido possível.fonte
Usando AngularJS 1.1.5
Atualizando a função 'phones' na resposta de Justen usando a sintaxe do AngularJS 1.1.5 .
Original:
Atualizada:
Muito mais curto, graças à equipe e colaboradores da Angular. :)
Esta é também a resposta de Maximilian Hoffmann. Aparentemente, esse commit entrou no 1.1.5.
fonte
$promise
nos documentos . Pode ter sido retirado a partir da v2.0 +.Você pode usar a propriedade $ routeProvider resolve para atrasar a alteração de rota até que os dados sejam carregados.
Observe que a
resolve
propriedade está definida na rota.EntitiesCtrlResolve
eEntityCtrlResolve
são objetos constantes definidos no mesmo arquivoEntitiesCtrl
e nosEntityCtrl
controladores.fonte
Gosto da ideia do darkporter porque será fácil para uma equipe de desenvolvimento nova do AngularJS entender e trabalhar imediatamente.
Eu criei essa adaptação que usa 2 divs, uma para a barra do carregador e outra para o conteúdo real exibido após o carregamento dos dados. O tratamento de erros seria feito em outro lugar.
Adicione um sinalizador 'pronto' ao $ scope:
Na visualização html:
Consulte também: Documentos da barra de progresso do Boostrap
fonte
Gostei das respostas acima e aprendi muito com elas, mas há algo que está faltando na maioria das respostas acima.
Eu estava preso em um cenário semelhante em que estava resolvendo o URL com alguns dados que foram buscados na primeira solicitação do servidor. O problema que enfrentei foi o que aconteceria se a promessa fosse
rejected
.Eu estava usando um provedor personalizado que usou para retornar um
Promise
que foi resolvido peloresolve
de$routeProvider
, no momento da fase de configuração.O que quero enfatizar aqui é o conceito de
when
que faz algo assim.Ele vê o URL na barra de URL e, em seguida, o respectivo
when
bloco no chamado controlador e a exibição é referida até agora como boa.Digamos que eu tenho o seguinte código de fase de configuração.
No URL raiz do navegador, o primeiro bloco de execução é chamado, caso contrário,
otherwise
é chamado.Vamos imaginar que um cenário em que eu carregue no rootUrl na
AuthServicePrivider.auth()
função da barra de endereço seja chamado.Vamos dizer que a promessa retornada está em estado de rejeição o que então ???
Nada é renderizado.
Otherwise
O bloco não será executado como é para qualquer URL que não esteja definido no bloco de configuração e seja desconhecido na fase de configuração do angularJs.Teremos que lidar com o evento que é acionado quando essa promessa não for resolvida. Em caso de falha
$routeChangeErorr
é acionado$rootScope
.Pode ser capturado como mostrado no código abaixo.
IMO Geralmente, é uma boa ideia colocar o código de rastreamento de eventos no bloco de aplicativos em execução. Este código é executado logo após a fase de configuração do aplicativo.
Dessa forma, podemos lidar com falhas prometidas no momento da fase de configuração.
fonte
Eu tive uma interface complexa de painel deslizante de vários níveis, com a camada de tela desativada. Criando diretiva para desativar a camada de tela que criaria um evento click para executar o estado como
estavam produzindo um efeito sacudindo. history.back () em vez de funcionar ok, no entanto, nem sempre está de volta à história no meu caso. Então, o que eu descobri é que, se eu simplesmente criar o atributo href na minha tela de desativação em vez de state.go, funcionaria como um encanto.
Diretiva 'voltar'
app.js Acabei de salvar o estado anterior
fonte
Uma solução possível pode ser usar a diretiva ng-cloak com o elemento em que estamos usando os modelos, por exemplo
Eu acho que este exige menos esforço.
fonte