J'ai implémenté une application de page unique angularjs en utilisant ui-router .
À l'origine, j'ai identifié chaque état en utilisant une URL distincte, mais cela rendait les URL compactées GUID peu conviviales.
J'ai donc défini mon site comme une machine à états beaucoup plus simple. Les états ne sont pas identifiés par des URL mais sont simplement transférés selon les besoins, comme ceci:
Définir des états imbriqués
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'
Transition vers un état défini
#The ui-sref attrib transitions to the 'folder' state
a(ui-sref="folder({locationId:'{{folder.Id}}'})")
| {{ folder.Name }}
Ce système fonctionne très bien et j'aime sa syntaxe propre. Cependant, comme je n'utilise pas d'URL, le bouton de retour ne fonctionne pas.
Comment puis-je conserver ma machine d'état soignée du routeur ui tout en activant la fonctionnalité du bouton de retour?
javascript
angularjs
coffeescript
angular-ui-router
biofractale
la source
la source
Réponses:
Remarque
Les réponses qui suggèrent d'utiliser des variantes de
$window.history.back()
ont toutes manqué une partie cruciale de la question: Comment restaurer l'état de l'application à l'emplacement d'état correct à mesure que l'historique saute (arrière / avant / actualisation). Dans cet esprit; s'il vous plaît, lisez la suite.Oui, il est possible d'avoir le navigateur en arrière / en avant (historique) et actualiser tout en exécutant une
ui-router
machine à états pure , mais cela prend un peu de travail.Vous avez besoin de plusieurs composants:
URL uniques . Le navigateur n'active les boutons Précédent / Suivant que lorsque vous modifiez les URL, vous devez donc générer une URL unique par état visité. Cependant, ces URL n'ont pas besoin de contenir d'informations d'état.
Un service de session . Chaque URL générée est corrélée à un état particulier, vous avez donc besoin d'un moyen de stocker vos paires url-état afin de pouvoir récupérer les informations d'état après le redémarrage de votre application angulaire par des clics arrière / avant ou d'actualisation.
Une histoire d'État . Un dictionnaire simple des états de ui-router avec une URL unique. Si vous pouvez compter sur HTML5, vous pouvez utiliser l' API d'Historique HTML5 , mais si, comme moi, vous ne pouvez pas, vous pouvez l'implémenter vous-même en quelques lignes de code (voir ci-dessous).
Un service de localisation . Enfin, vous devez être en mesure de gérer à la fois les changements d'état de l'interface utilisateur, déclenchés en interne par votre code, et les changements d'URL normaux du navigateur généralement déclenchés par l'utilisateur cliquant sur les boutons du navigateur ou en tapant des éléments dans la barre du navigateur. Tout cela peut devenir un peu délicat car il est facile de se demander ce qui a déclenché quoi.
Voici ma mise en œuvre de chacune de ces exigences. J'ai tout regroupé en trois services:
Le service de session
Ceci est un wrapper pour l'
sessionStorage
objet javascript . Je l'ai réduit pour plus de clarté ici. Pour une explication complète de cela, veuillez consulter: Comment gérer l'actualisation de la page avec une application à une seule page AngularJSLe service d'histoire de l'État
Il
StateHistoryService
s'occupe du stockage et de la récupération des états historiques définis par des URL uniques générées. C'est vraiment juste un wrapper pratique pour un objet de style dictionnaire.Le service de localisation d'État
Le
StateLocationService
gère deux événements:locationChange . Ceci est appelé lorsque l'emplacement du navigateur est modifié, généralement lorsque vous appuyez sur le bouton Précédent / Suivant / Actualiser ou lorsque l'application démarre pour la première fois ou lorsque l'utilisateur tape une URL. Si un état pour l'emplacement actuel.url existe dans le,
StateHistoryService
il est utilisé pour restaurer l'état via ui-routeur$state.go
.stateChange . Ceci est appelé lorsque vous déplacez l'état en interne. Le nom et les paramètres de l'état actuel sont stockés dans la
StateHistoryService
clé par une URL générée. Cette URL générée peut être tout ce que vous voulez, elle peut ou non identifier l'état d'une manière lisible par l'homme. Dans mon cas, j'utilise un paramètre d'état plus une séquence de chiffres générée aléatoirement dérivée d'un guid (voir le pied de page pour l'extrait du générateur de guid). L'URL générée est affichée dans la barre du navigateur et, surtout, ajoutée à la pile d'historique interne du navigateur à l'aide de@location.url url
. Il ajoute l'URL à la pile d'historique du navigateur qui active les boutons avant / arrière.Le gros problème avec cette technique est que l'appel
@location.url url
de lastateChange
méthode déclenchera l'$locationChangeSuccess
événement et appellera donc lalocationChange
méthode. De même, l'appel de@state.go
fromlocationChange
déclenchera l'$stateChangeSuccess
événement et donc lastateChange
méthode. Cela devient très déroutant et gâche l'historique du navigateur sans fin.La solution est très simple. Vous pouvez voir le
preventCall
tableau utilisé comme pile (pop
etpush
). Chaque fois qu'une des méthodes est appelée, elle empêche que l'autre méthode ne soit appelée une seule fois. Cette technique n'interfère pas avec le déclenchement correct des événements $ et maintient tout droit.Il ne nous reste plus qu'à appeler les
HistoryService
méthodes au moment opportun dans le cycle de vie de la transition d'état. Cela se fait dans la.run
méthode AngularJS Apps , comme ceci:App.run angulaire
Générer un Guid
Avec tout cela en place, les boutons avant / arrière et le bouton d'actualisation fonctionnent tous comme prévu.
la source
@setStorage
et@getStorage
plutôt que `@ get / setSession '.$window.history.back()
ont manqué une partie cruciale de la question. Le but était de restaurer l' état de l'application à l'emplacement d'état correct au fur et à mesure que l'historique saute (arrière / avant / actualisation). Ceci serait normalement réalisé en fournissant les données d'état via l'URI. La question demandait comment sauter entre les emplacements d'état sans données d'état URI (explicites). Compte tenu de cette contrainte, il n'est pas suffisant de simplement répliquer le bouton de retour car cela repose sur les données d'état de l'URI pour rétablir l'emplacement de l'état.la source
$window.history.back
faut pas faire de magie$rootScope
... donc revenir en arrière pourrait être lié à votre champ d'application de la directive de la barre de navigation si vous le souhaitez.$window.history.back();
dans une fonction à appelerng-click
.Après avoir testé différentes propositions, j'ai trouvé que le moyen le plus simple est souvent le meilleur.
Si vous utilisez un ui-router angulaire et que vous avez besoin d'un bouton pour revenir en arrière, voici:
ou
// Attention, ne définissez pas le href ou le chemin sera cassé.
Explication: Supposons une application de gestion standard. Rechercher un objet -> Afficher l'objet -> Modifier l'objet
Utilisation des solutions angulaires À partir de cet état:
À :
Eh bien, c'est ce que nous voulions sauf si maintenant vous cliquez sur le bouton de retour du navigateur, vous y serez à nouveau:
Et ce n'est pas logique
Cependant en utilisant la solution simple
de :
après avoir cliqué sur le bouton:
après avoir cliqué sur le bouton de retour du navigateur:
La cohérence est respectée. :-)
la source
Si vous recherchez le bouton "retour" le plus simple, vous pouvez configurer une directive comme celle-ci:
Gardez à l'esprit qu'il s'agit d'un bouton "retour" assez peu intelligent car il utilise l'historique du navigateur. Si vous l'incluez sur votre page de destination, il renverra un utilisateur à n'importe quelle URL d'où il provient avant d'atterrir sur la vôtre.
la source
solution du bouton Précédent / Suivant du navigateur
J'ai rencontré le même problème et je l'ai résolu en utilisant l'objet
popstate event
de $ window etui-router's $state object
. Un événement popstate est envoyé à la fenêtre chaque fois que l'entrée d'historique active change.Les événements
$stateChangeSuccess
et$locationChangeSuccess
ne sont pas déclenchés lors du clic du bouton du navigateur, même si la barre d'adresse indique le nouvel emplacement.Donc, en supposant que vous avez navigué des Etats
main
àfolder
lamain
fois, lorsque vous appuyezback
sur le navigateur, vous devez être de retour à l'folder
itinéraire. Le chemin est mis à jour mais la vue ne l'est pas et affiche toujours tout ce que vous avezmain
. essaye ça:les boutons Précédent / Suivant devraient fonctionner correctement après cela.
Remarque: vérifiez la compatibilité du navigateur pour window.onpopstate () pour être sûr
la source
Peut être résolu en utilisant une simple directive "go-back-history", celle-ci ferme également la fenêtre en cas d'absence d'historique précédent.
Utilisation de la directive
Déclaration de directive angulaire
Remarque: Travailler avec ui-router ou non.
la source
Le bouton Retour ne fonctionnait pas non plus pour moi, mais j'ai compris que le problème était que j'avais du
html
contenu dans ma page principale, dans l'ui-view
élément.c'est à dire
J'ai donc déplacé le contenu dans un nouveau
.html
fichier et l' ai marqué comme modèle dans le.js
fichier avec les itinéraires.c'est à dire
la source
history.back()
et passer à l'état précédent donnent souvent l'effet que vous ne voulez pas. Par exemple, si vous avez un formulaire avec des onglets et que chaque onglet a son propre état, cet onglet précédent vient de basculer sélectionné, pas de retour du formulaire. Dans le cas d'états imbriqués, vous devez généralement penser à la sorcière des états parents que vous souhaitez restaurer.Cette directive résout le problème
Il revient à l'état, qui était actif avant que le bouton ne s'affiche. Facultatif
defaultState
est le nom d'état utilisé lorsqu'il n'y a pas d'état précédent en mémoire. Il restaure également la position de défilementCode
la source