Implementei um aplicativo de página única angularjs usando ui-router .
Originalmente, identifiquei cada estado usando um url distinto, mas isso tornava urls compactadas com GUID hostis.
Portanto, agora defini meu site como uma máquina de estados muito mais simples. Os estados não são identificados por urls, mas são simplesmente transferidos conforme necessário, como este:
Definir estados aninhados
angular
.module 'app', ['ui.router']
.config ($stateProvider) ->
$stateProvider
.state 'main',
templateUrl: 'main.html'
controller: 'mainCtrl'
params: ['locationId']
.state 'folder',
templateUrl: 'folder.html'
parent: 'main'
controller: 'folderCtrl'
resolve:
folder:(apiService) -> apiService.get '#base/folder/#locationId'
Transição para um estado definido
#The ui-sref attrib transitions to the 'folder' state
a(ui-sref="folder({locationId:'{{folder.Id}}'})")
| {{ folder.Name }}
Este sistema funciona muito bem e adoro sua sintaxe limpa. No entanto, como não estou usando urls, o botão Voltar não funciona.
Como mantenho minha máquina de estado ui-router organizada, mas habilito a funcionalidade do botão Voltar?
javascript
angularjs
coffeescript
angular-ui-router
biofractal
fonte
fonte
Respostas:
Nota
Todas as respostas que sugerem o uso de variações de
$window.history.back()
perderam uma parte crucial da questão: como restaurar o estado do aplicativo para o local de estado correto conforme o histórico pula (voltar / avançar / atualizar). Com aquilo em mente; por favor, continue a ler.Sim, é possível retroceder / avançar (histórico) e atualizar o navegador durante a execução de uma
ui-router
máquina de estado puro , mas isso demora um pouco.Você precisa de vários componentes:
URLs exclusivos . O navegador só ativa os botões voltar / avançar quando você altera os urls, portanto, você deve gerar um url exclusivo para cada estado visitado. No entanto, esses urls não precisam conter nenhuma informação de estado.
Um serviço de sessão . Cada url gerado é correlacionado a um estado específico, portanto, você precisa de uma maneira de armazenar seus pares de url-estado para que possa recuperar as informações de estado depois que seu aplicativo angular foi reiniciado por retroceder / avançar ou cliques de atualização.
Uma História do Estado . Um dicionário simples de estados do roteador da interface do usuário codificados por url exclusivo. Se você pode confiar no HTML5, então você pode usar a API HTML5 History , mas se, como eu, você não pode, então você pode implementá-lo em algumas linhas de código (veja abaixo).
Um serviço de localização . Finalmente, você precisa ser capaz de gerenciar as alterações de estado do roteador da interface do usuário, acionadas internamente por seu código, e as alterações normais de URL do navegador, normalmente acionadas pelo usuário clicando nos botões do navegador ou digitando coisas na barra do navegador. Isso tudo pode ser um pouco complicado porque é fácil ficar confuso sobre o que acionou o quê.
Aqui está minha implementação de cada um desses requisitos. Eu agrupei tudo em três serviços:
O Serviço de Sessão
Este é um wrapper para o
sessionStorage
objeto javascript . Eu o cortei para maior clareza aqui. Para obter uma explicação completa sobre isso, consulte: Como faço para atualizar a página com um aplicativo de página única AngularJSO Serviço de História do Estado
O
StateHistoryService
cuidado com o armazenamento e recuperação de estados históricos digitados por urls únicas geradas. Na verdade, é apenas um invólucro prático para um objeto de estilo de dicionário.O Serviço de Localização Estadual
O
StateLocationService
trata de dois eventos:locationChange . Isso é chamado quando a localização do navegador é alterada, normalmente quando o botão voltar / avançar / atualizar é pressionado ou quando o aplicativo é iniciado pela primeira vez ou quando o usuário digita um url. Se um estado para o location.url atual existir no
StateHistoryService
, ele será usado para restaurar o estado por meio do ui-roteador$state.go
.stateChange . Isso é chamado quando você move o estado internamente. O nome e os parâmetros do estado atual são armazenados no
StateHistoryService
digitado por um url gerado. Este url gerado pode ser o que você quiser, ele pode ou não identificar o estado de uma forma legível por humanos. No meu caso, estou usando um parâmetro de estado mais uma sequência de dígitos gerada aleatoriamente, derivada de um guid (consulte o pé para o trecho do gerador de guid). O url gerado é exibido na barra do navegador e, principalmente, adicionado à pilha de histórico interno do navegador usando@location.url url
. É adicionar o url à pilha de histórico do navegador que habilita os botões avançar / voltar.O grande problema com essa técnica é que chamar
@location.url url
ostateChange
método irá disparar o$locationChangeSuccess
evento e então chamar olocationChange
método. Igualmente, chamar o@state.go
fromlocationChange
irá disparar o$stateChangeSuccess
evento e, portanto, ostateChange
método. Isso fica muito confuso e bagunça o histórico do navegador sem fim.A solução é muito simples. Você pode ver a
preventCall
matriz sendo usada como uma pilha (pop
epush
). Cada vez que um dos métodos é chamado, ele evita que o outro método seja chamado apenas uma vez. Essa técnica não interfere no disparo correto dos $ events e mantém tudo correto.Agora tudo o que precisamos fazer é chamar os
HistoryService
métodos no momento apropriado no ciclo de vida de transição de estado. Isso é feito no.run
método AngularJS Apps , como este:Angular app.run
Gerar um Guid
Com tudo isso no lugar, os botões avançar / voltar e o botão Atualizar funcionam como esperado.
fonte
@setStorage
e em@getStorage
vez de `@ get / setSession '.$window.history.back()
perderam uma parte crucial da pergunta. O objetivo era restaurar o estado do aplicativo para o local de estado correto conforme o histórico pula (voltar / avançar / atualizar). Isso normalmente seria obtido fornecendo os dados de estado por meio do URI. A questão perguntada como pular entre locais de estado sem dados de estado de URI (explícitos). Dada essa restrição, não é suficiente apenas replicar o botão Voltar, porque isso depende dos dados de estado do URI para restabelecer a localização do estado.fonte
$window.history.back
está fazendo a mágica$rootScope
... então volte pode ser vinculado ao escopo da sua diretiva navbar se quiser.$window.history.back();
em uma função a ser chamadang-click
.Depois de testar diferentes propostas, descobri que a maneira mais fácil costuma ser a melhor.
Se você usa ui-roteador angular e precisa de um botão para voltar, é o seguinte:
ou
// Aviso, não defina o href ou o caminho será quebrado.
Explicação: Suponha um aplicativo de gerenciamento padrão. Objeto de pesquisa -> Exibir objeto -> Editar objeto
Usando as soluções angulares a partir deste estado:
Para :
Bem, isso é o que queríamos, exceto se agora você clicar no botão Voltar do navegador, você estará lá novamente:
E isso não é lógico
No entanto, usando a solução simples
de :
depois de clicar no botão:
depois de clicar no botão Voltar do navegador:
A consistência é respeitada. :-)
fonte
Se você está procurando o botão "voltar" mais simples, pode configurar uma diretiva como esta:
Lembre-se de que este é um botão "voltar" bastante pouco inteligente porque está usando o histórico do navegador. Se você incluí-lo em sua página de destino, ele enviará o usuário de volta a qualquer url de onde veio antes de acessar o seu.
fonte
solução do botão voltar / avançar do navegador
Encontrei o mesmo problema e resolvi-o usando o
popstate event
objeto da janela $ eui-router's $state object
. Um evento popstate é despachado para a janela sempre que a entrada ativa do histórico é alterada.Os eventos
$stateChangeSuccess
e$locationChangeSuccess
não são acionados no clique do botão do navegador, embora a barra de endereço indique o novo local.Assim, supondo que você tenha navegado dos estados
main
parafolder
amain
outra vez, quando você bateback
no navegador, você deve estar de volta àfolder
rota. O caminho é atualizado, mas a visualização não é e ainda exibe tudo o que você temmain
. tente isto:os botões voltar / avançar devem funcionar sem problemas depois disso.
nota: verifique a compatibilidade do navegador para window.onpopstate () para ter certeza
fonte
Pode ser resolvido usando uma simples diretiva "go-back-history", esta também fecha a janela caso não haja histórico anterior.
Uso de diretiva
Declaração de diretiva angular
Nota: Trabalhar usando ui-router ou não.
fonte
O botão Voltar não estava funcionando bem para mim, mas descobri que o problema era que eu tinha
html
conteúdo dentro da minha página principal, noui-view
elemento.ie
Então, movi o conteúdo para um novo
.html
arquivo e marquei-o como um modelo no.js
arquivo com as rotas.ie
fonte
history.back()
e alternar para o estado anterior geralmente dá o efeito que você deseja. Por exemplo, se você tiver um formulário com guias e cada guia tiver seu próprio estado, isso apenas alternará a guia anterior selecionada, não retornará do formulário. No caso de estados aninhados, você geralmente precisa pensar sobre quais estados pai deseja reverter.Esta diretiva resolve o problema
Ele retorna ao estado que estava ativo antes de o botão ser exibido. Opcional
defaultState
é o nome do estado usado quando não há estado anterior na memória. Também restaura a posição de rolagemCódigo
fonte