Enrutador AngularJS UI: cambie la URL sin tener que volver a cargar el estado

Actualmente nuestro proyecto está usando $routeProvider predeterminado, y estoy usando este “hack” para cambiar la url sin cargar la página:

 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; }]); 

y en el controller

 $locationEx.skipReload().path("/category/" + $scope.model.id).replace(); 

Estoy pensando en reemplazar routeProvider con ui-router para rutas de anidamiento, pero no puedo encontrar esto en ui-router .

¿Es posible? Haz lo mismo con angular-ui-router ?

¿Por qué necesito esto? Dejame explicarte con un ejemplo :
La ruta para crear una categoría nueva es /category/new después de clicking en SAVE. Mostrar show success-alert y quiero cambiar route /category/new en /caterogy/23 (23 – es id del nuevo elemento almacenado en db)

Simplemente puede usar $state.transitionTo lugar de $state.go . $state.go llama $state.transitionTo interna pero establece automáticamente las opciones en { location: true, inherit: true, relative: $state.$current, notify: true } . Puede llamar $state.transitionTo y establecer $state.transitionTo notify: false . Por ejemplo:

 $state.go('.detail', {id: newId}) 

puede ser reemplazado por

 $state.transitionTo('.detail', {id: newId}, { location: true, inherit: true, relative: $state.$current, notify: false }) 

Editar: Según lo sugerido por fracz, simplemente puede ser:

 $state.go('.detail', {id: newId}, {notify: false}) 

Ok, resuelto 🙂 Angular UI Router tiene este nuevo método, $ urlRouterProvider.deferIntercept () https://github.com/angular-ui/ui-router/issues/64

Básicamente se trata de esto:

 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(); }]); 

Creo que este método actualmente solo está incluido en la versión maestra del enrutador ui angular, el que tiene parámetros opcionales (que también son agradables, por cierto). Necesita ser clonado y construido desde la fuente con

 grunt build 

Los documentos son accesibles desde la fuente también, a través de

 grunt ngdocs 

(se integran en el directorio / site) // más información en README.MD

Parece que hay otra forma de hacerlo, mediante parámetros dynamics (que no he usado). Muchos créditos a nateabele.


Como nota al margen, aquí hay parámetros opcionales en $ stateProvider de Router de UI Angular, que utilicé en combinación con lo anterior:

 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' }); }]); 

lo que hace es que permite resolver un estado, incluso si falta uno de los params. SEO es un propósito, legibilidad otro.

En el ejemplo anterior, quería que doorsSingle fuera un parámetro obligatorio. No está claro cómo definirlos. Sin embargo, funciona bien con múltiples parámetros opcionales, por lo que realmente no es un problema. La discusión está aquí https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090

Después de pasar mucho tiempo con este problema, esto es lo que obtuve trabajando

 $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 }); 

Esta configuración resolvió los siguientes problemas para mí:

  • El controlador de entrenamiento no se llama dos veces cuando se actualiza la URL de .../ a .../123
  • El controlador de entrenamiento no se vuelve a invocar cuando navega hacia otro estado

Configuración del estado

 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 } }) 

Invocando los estados (de cualquier otro controlador)

 $scope.editTraining = function (training) { $state.go('training.edit', { trainingId: training.id }); }; $scope.newTraining = function () { $state.go('training.new', { }); }; 

Controlador de entrenamiento

 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 ... } 

Lo hice hace mucho tiempo en la versión: v0.2.10 del enrutador UI, algo como esto ::

 $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 }) 

Si solo necesita cambiar la url pero evita el cambio de estado:

Cambie la ubicación con (agregue .replace si desea reemplazar en el historial):

 this.$location.path([Your path]).replace(); 

Evite la redirección a su estado:

 $transitions.onBefore({}, function($transition$) { if ($transition$.$to().name === '[state name]') { return false; } }); 

Pruebe algo como esto

 $state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false}) 

No creo que necesites un enrutador ui para nada. La documentación disponible para el servicio $ location dice en el primer párrafo, “… los cambios en $ location se reflejan en la barra de direcciones del navegador”. Continúa más tarde para decir: “¿Qué no hace? No causa una recarga de página completa cuando se cambia la URL del navegador”.

Entonces, teniendo esto en cuenta, ¿por qué no simplemente cambiar $ location.path (ya que el método es tanto getter como setter) con algo como lo siguiente:

 var newPath = IdFromService; $location.path(newPath); 

La documentación indica que la ruta siempre debe comenzar con una barra inclinada, pero esto la agregará si falta.