Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Currently our project using default $routeProvider, and i using this "hack", to change url without reloading 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;
}]);

and in controller

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

I thinking of replace routeProvider with Ui-Router for nesting routes, but cant find this in UI-Router.

Is this possible - do the same with Angular UI-ROUTER?

Why i need this? Ex: Route for creating new category is /category/new after click SAVE i show success-alert and i want change route /category/new to /caterogy/23 (23 - is id of new item stored in db)

share|improve this question
    
in ui-router you dont have to define a URL for each states, you can navigate from state to state without changing URL –  Jonathan de M. May 10 '14 at 19:10
    
do you want to update the whole URL or just the search path? I was searching for a solution updating the search path and found it over here: stackoverflow.com/questions/21425378/… –  Florian Loch Jul 26 '14 at 12:06

4 Answers 4

up vote 13 down vote accepted

Ok, solved :) Angular UI Router has this new method, $urlRouterProvider.deferIntercept() https://github.com/angular-ui/ui-router/issues/64

basically it comes down to this:

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

I think this method is currently only included in the master version of angular ui router, the one with optional parameters (which are nice too, btw). It needs to be cloned and built from source with

grunt build

The docs are accessible from the source as well, through

grunt ngdocs

(they get built into the /site directory) // more info in README.MD

There seems to be another way to do this, by dynamic parameters (which I haven't used). Many credits to nateabele.


As a sidenote, here are optional parameters in Angular UI Router's $stateProvider, which I used in combination with the above:

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

}]);

what that does is it allows to resolve a state, even if one of the params is missing. SEO is one purpose, readability another.

In the example above, I wanted doorsSingle to be a required parameter. It is not clear how to define those. It works ok with multiple optional parameters though, so not really a problem. The discussion is here https://github.com/angular-ui/ui-router/pull/1032#issuecomment-49196090

share|improve this answer
    
It seems that your optional parameters thing doesn't work. Error: Both params and url specicified in state 'state'. It says in the docs that this is invalid usage too. A bit disappointing. –  Rhys van der Waerden Aug 28 '14 at 7:41
1  
Did you build from master? Please note that at the point when I added the solution, the optional parameters was only included in the version that had to be built manually from source. this will not be included in the release until v.0.3 is out. –  wiherek Aug 28 '14 at 10:40
1  
Just a quick note. Thanks to nateabele the optional parameters are available in v0.2.11 which was just released a few days ago. –  rich97 Sep 3 '14 at 8:16

Simply you can use $state.transitionTo instead of $state.go . $state.go calls $state.transitionTo internally but automatically sets options to { location: true, inherit: true, relative: $state.$current, notify: true } . You can call $state.transitionTo and set location: false . For example:

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

can be replaced by

 $state.transitionTo ('.detail', {id: newId}, { location: false, inherit: true, relative: $state.$current, notify: true }) 
share|improve this answer
3  
Isn't that "keep url when reloading state" instead of "change url without reloading state"? –  Peter Hedberg Sep 19 '14 at 9:06
    
No! It exactly keeps state and changes url! –  rezCash Oct 1 '14 at 16:45
7  
for me it worked with the following: $state.transitionTo('.detail', {id: newId}, { location: true, inherit: true, relative: $state.$current, notify: false }) so basically set notify to false and location to true –  Arjen de Vries Oct 6 '14 at 15:13
    
The url never gets updated in Chrome. Has it been changes here the last couple of months? –  Remi Sture Nov 2 '14 at 17:41
1  
@ArjendeVries Yes it is working as expected but I found an unexpected behavior. After playing around with many transitionTo method call (without reloading) when you finally moving to a new state (ie. url), it re-initiate old controller. –  Premchandra Singh Dec 26 '14 at 11:56

This setup solved following issues for me:

  • The training controller is not called twice when updating the url from .../ to .../123
  • The training controller is not getting invoked again when navigating to another state

State configuration

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

Invoking the states (from any other controller)

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

$scope.newTraining = function () {
    $state.go('training.new', { });
};

Training Controller

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 ...
}   
share|improve this answer

I don't think you need ui-router at all for this. The documentation available for the $location service says in the first paragraph, "...changes to $location are reflected into the browser address bar." It continues on later to say, "What does it not do? It does not cause a full page reload when the browser URL is changed."

So, with that in mind, why not simply change the $location.path (as the method is both a getter and setter) with something like the following:

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

The documentation notes that the path should always begin with a forward slash, but this will add it if it's missing.

share|improve this answer
    
When I use ui-router, and use $location.path(URL_PATH), the page automatically re-renders?! –  Kousha Jul 8 '14 at 2:11
    
yeah, it re-renders. I tried with event.preventDefault() on $locationChangeStart, that doesn't work either - i.e. it stops the state from re-rendering, but it also prevents the url from updating. –  wiherek Jul 17 '14 at 16:56

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.