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)

121
demandé sur imsheth 2014-05-10 22:56:37

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}) 
145
répondu rezCash 2017-04-12 14:58:14

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

47
répondu wiherek 2014-10-08 00:10:11

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
});
13
répondu Pankaj Parkar 2015-09-02 14:31:11

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 ...
}   
7
répondu martinoss 2014-12-28 14:12:23

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;
 }
});
3
répondu egor.xyz 2017-10-26 08:51:20

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
  })
2
répondu sheelpriy 2015-12-23 09:04:32

Essayez quelque chose comme ça

$state.go($state.$current.name, {... $state.params, 'key': newValue}, {notify: false})
0
répondu Eyad Farra 2018-07-24 19:12:47

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.

-6
répondu Xaniff 2014-07-08 03:33:56