AngularJS UI Router – cambia l’url senza lo stato di ricaricamento

Attualmente il nostro progetto utilizza $routeProvider predefinito e sto usando questo “hack” per modificare l’ url senza ricaricare la pagina:

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

e nel controller

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

Sto pensando di sostituire routeProvider con ui-router per i percorsi di nidificazione, ma non riesco a trovarlo in ui-router .

È ansible – fare lo stesso con angular-ui-router ?

Perché ho bisogno di questo? Lasciatemi spiegare con un esempio:
Il percorso per creare una nuova categoria è /category/new dopo aver clicking su SAVE I mostra success-alert e voglio cambiare rotta /category/new in /caterogy/23 (23 – è id del nuovo object memorizzato in db)

Semplicemente puoi usare $state.transitionTo invece di $state.go . $state.go chiama $state.transitionTo internamente, ma imposta automaticamente le opzioni su { location: true, inherit: true, relative: $state.$current, notify: true } . Puoi chiamare $state.transitionTo e impostare notify: false . Per esempio:

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

può essere sostituito da

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

Modifica: come suggerito da fracz può essere semplicemente:

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

Ok, risolto 🙂 Angular UI Router ha questo nuovo metodo, $ urlRouterProvider.deferIntercept () https://github.com/angular-ui/ui-router/issues/64

fondamentalmente si tratta di questo:

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

Penso che questo metodo sia attualmente incluso solo nella versione master del router ui angular, quello con i parametri opzionali (che sono anche carini, btw). Deve essere clonato e costruito dalla sorgente con

 grunt build 

I documenti sono accessibili anche dalla fonte, attraverso

 grunt ngdocs 

(vengono incorporati nella directory / site) // maggiori informazioni in README.MD

Sembra esserci un altro modo per farlo, con parametri dinamici (che non ho usato). Molti crediti a nateabele.


Come sidenote, qui ci sono i parametri opzionali nel $ stateProvider del router UI angular, che ho usato in combinazione con quanto sopra:

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

ciò che fa è che permette di risolvere uno stato, anche se manca uno dei parametri. La SEO è uno scopo, la leggibilità un’altra.

Nell’esempio sopra, volevo che DoorsSingle fosse un parametro obbligatorio. Non è chiaro come definirli. Funziona bene con molti parametri opzionali, quindi non è un problema. La discussione è qui https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090

Dopo aver trascorso molto tempo con questo problema, ecco cosa ho lavorato

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

Questa configurazione ha risolto i seguenti problemi per me:

  • Il controller di allenamento non viene chiamato due volte quando aggiorna l’url da .../ a .../123
  • Il controller di allenamento non viene richiamato nuovamente quando si naviga in un altro stato

Configurazione dello stato

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

Richiamo degli stati (da qualsiasi altro controller)

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

Controller di allenamento

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

Ho fatto questo, ma molto tempo fa nella versione: v0.2.10 di UI-router come qualcosa del genere ::

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

Se hai solo bisogno di modificare l’url ma prevenire lo stato di modifica:

Cambia posizione con (aggiungi .replace se vuoi sostituire nella cronologia):

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

Impedisci il reindirizzamento al tuo stato:

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

Prova qualcosa di simile

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

Non penso che tu abbia bisogno di un router per nulla per questo. La documentazione disponibile per il servizio $ location dice nel primo paragrafo, “… le modifiche a $ posizione si riflettono nella barra degli indirizzi del browser.” Successivamente continua dicendo: “Cosa non fa? Non causa il ricaricamento di una pagina intera quando l’URL del browser viene modificato”.

Quindi, tenendo presente questo, perché non cambiare semplicemente $ location.path (poiché il metodo è sia getter che setter) con qualcosa di simile al seguente:

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

La documentazione rileva che il percorso dovrebbe sempre iniziare con una barra in avanti, ma questa verrà aggiunta se manca.