AngularJS UI routeur-changer l'url sans recharger l'état
actuellement notre projet utilise par défaut $routeProvider
, et j'utilise ce "hack", pour changer url
sans recharger la page:
services.service('$locationEx', ['$location', '$route', '$rootScope', function($location, $route, $rootScope) {
$location.skipReload = function () {
var lastRoute = $route.current;
var un = $rootScope.$on('$locationChangeSuccess', function () {
$route.current = lastRoute;
un();
});
return $location;
};
return $location;
}]);
et dans controller
$locationEx.skipReload().path("/category/" + $scope.model.id).replace();
je pense remplacer routeProvider
par ui-router
pour les itinéraires de nidification, mais je ne trouve pas cela dans ui-router
.
est - il possible de faire la même chose avec angular-ui-router
?
Pourquoi ai-je besoin cette?
Permettez-moi d'expliquer avec un exemple:
La Route pour créer une nouvelle catégorie est /category/new
après clicking
sur ENREGISTRER je montre success-alert
et je veux changer de route /category/new
à /caterogy/23
(23 - est l'id du nouveau élément stocké dans la bd)
8 réponses
vous pouvez simplement utiliser $state.transitionTo
au lieu de $state.go
. $state.go
appelle $state.transitionTo
en interne mais définit automatiquement les options à { location: true, inherit: true, relative: $state.$current, notify: true }
. Vous pouvez appeler $state.transitionTo
et mettre notify: false
. Par exemple:
$state.go('.detail', {id: newId})
peut être remplacé par
$state.transitionTo('.detail', {id: newId}, {
location: true,
inherit: true,
relative: $state.$current,
notify: false
})
Edit: comme suggéré par fracz il peut simplement être:
$state.go('.detail', {id: newId}, {notify: false})
Ok, résolu :) Le routeur D'UI angulaire a cette nouvelle méthode, $urlRouterProvider.déférintercept() https://github.com/angular-ui/ui-router/issues/64
fondamentalement, il se résume à ceci:
angular.module('myApp', [ui.router])
.config(['$urlRouterProvider', function ($urlRouterProvider) {
$urlRouterProvider.deferIntercept();
}])
// then define the interception
.run(['$rootScope', '$urlRouter', '$location', '$state', function ($rootScope, $urlRouter, $location, $state) {
$rootScope.$on('$locationChangeSuccess', function(e, newUrl, oldUrl) {
// Prevent $urlRouter's default handler from firing
e.preventDefault();
/**
* provide conditions on when to
* sync change in $location.path() with state reload.
* I use $location and $state as examples, but
* You can do any logic
* before syncing OR stop syncing all together.
*/
if ($state.current.name !== 'main.exampleState' || newUrl === 'http://some.url' || oldUrl !=='https://another.url') {
// your stuff
$urlRouter.sync();
} else {
// don't sync
}
});
// Configures $urlRouter's listener *after* your custom listener
$urlRouter.listen();
}]);
je pense que cette méthode n'est actuellement incluse que dans la version master de routeur ui angulaire, celui avec des paramètres optionnels (qui sont bien aussi, btw). Il doit être cloné et construit à partir de la source avec
grunt build
Les documents sont accessibles à partir de la source, par le biais de
grunt ngdocs
(ils sont intégrés dans le répertoire /site) // more info in README.MD
il semble y avoir une autre façon de le faire, par les paramètres dynamiques (que je n'ai pas utilisé). Beaucoup de crédits à nateabele.
comme un sidenote, voici paramètres optionnels dans le $stateProvider de router UI angulaire, que j'ai utilisé en combinaison avec ce qui précède:
angular.module('myApp').config(['$stateProvider', function ($stateProvider) {
$stateProvider
.state('main.doorsList', {
url: 'doors',
controller: DoorsListCtrl,
resolve: DoorsListCtrl.resolve,
templateUrl: '/modules/doors/doors-list.html'
})
.state('main.doorsSingle', {
url: 'doors/:doorsSingle/:doorsDetail',
params: {
// as of today, it was unclear how to define a required parameter (more below)
doorsSingle: {value: null},
doorsDetail: {value: null}
},
controller: DoorsSingleCtrl,
resolve: DoorsSingleCtrl.resolve,
templateUrl: '/modules/doors/doors-single.html'
});
}]);
ce que cela fait est qu'il permet de résoudre un etat, même si l'un des paramètres est manquant. SEO est un objectif, la lisibilité de l'autre.
dans l'exemple ci-dessus, je voulais que doorsSingle soit un paramètre requis. On ne sait pas très bien comment les définir. Il fonctionne bien avec plusieurs paramètres facultatifs, donc pas vraiment un problème. La discussion est ici https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090
après avoir passé beaucoup de temps avec ce numéro, voici ce que j'ai obtenu de travailler
$state.go('stateName',params,{
// prevent the events onStart and onSuccess from firing
notify:false,
// prevent reload of the current state
reload:false,
// replace the last record when changing the params so you don't hit the back button and get old params
location:'replace',
// inherit the current params on the url
inherit:true
});
cette configuration a résolu les problèmes suivants pour moi:
- le contrôleur de formation n'est pas appelé deux fois lors de la mise à jour de l'url de
.../
à.../123
- le contrôleur de la formation n'est pas invoqué de nouveau lorsqu'il navigue vers un autre État
configuration de l'État de
state('training', {
abstract: true,
url: '/training',
templateUrl: 'partials/training.html',
controller: 'TrainingController'
}).
state('training.edit', {
url: '/:trainingId'
}).
state('training.new', {
url: '/{trainingId}',
// Optional Parameter
params: {
trainingId: null
}
})
invoquant les États (de toute autre contrôleur)
$scope.editTraining = function (training) {
$state.go('training.edit', { trainingId: training.id });
};
$scope.newTraining = function () {
$state.go('training.new', { });
};
Contrôleur De Formation
var newTraining;
if (!!!$state.params.trainingId) {
// new
newTraining = // create new training ...
// Update the URL without reloading the controller
$state.go('training.edit',
{
trainingId : newTraining.id
},
{
location: 'replace', // update url and replace
inherit: false,
notify: false
});
} else {
// edit
// load existing training ...
}
si vous n'avez besoin que de changer l'url mais d'empêcher le changement d'état:
changer de lieu avec (add .Remplacer si vous voulez remplacer dans l'histoire):
this.$location.path([Your path]).replace();
empêcher de rediriger vers votre état:
$transitions.onBefore({}, function($transition$) {
if ($transition$.$to().name === '[state name]') {
return false;
}
});
j'ai fait ceci mais il y a longtemps dans la version: v0.2.10 de UI-router comme quelque chose comme ceci::
$stateProvider
.state(
'home', {
url: '/home',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('shared/partial/main.html'),
controller: 'mainCtrl'
},
}
})
.state('home.login', {
url: '/login',
templateUrl: Url.resolveTemplateUrl('authentication/partial/login.html'),
controller: 'authenticationCtrl'
})
.state('home.logout', {
url: '/logout/:state',
controller: 'authenticationCtrl'
})
.state('home.reservationChart', {
url: '/reservations/?vw',
views: {
'': {
templateUrl: Url.resolveTemplateUrl('reservationChart/partial/reservationChartContainer.html'),
controller: 'reservationChartCtrl',
reloadOnSearch: false
},
'viewVoucher@home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/viewVoucherContainer.html'),
controller: 'viewVoucherCtrl',
reloadOnSearch: false
},
'addEditVoucher@home.reservationChart': {
templateUrl: Url.resolveTemplateUrl('voucher/partial/voucherContainer.html'),
controller: 'voucherCtrl',
reloadOnSearch: false
}
},
reloadOnSearch: false
})
Essayez quelque chose comme ça
$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})
Je ne pense pas que vous ayez besoin d'un routeur ui pour cela. La documentation disponible pour le $location service dit dans le premier paragraphe, "...les changements à $location sont reflétés dans la barre d'adresse du navigateur."Il continue plus tard à dire," Qu'est-ce qu'il ne fait pas? Il ne provoque pas une page complète recharger lorsque l'URL du navigateur est modifié."
Donc, avec cela à l'esprit, pourquoi ne pas simplement changer l'emplacement$.chemin (comme la méthode est à la fois un getter et setter) avec quelque chose comme ce qui suit:
var newPath = IdFromService;
$location.path(newPath);
la documentation note que le chemin doit toujours commencer par une barre oblique avant, mais cela l'ajoutera s'il est manquant.