51
<h1>{{header}}</h1>
<!-- This Back button has multiple option -->
<!-- In home page it will show menu -->
<!-- In other views it will show back link -->
<a ng-href="{{back.url}}">{{back.text}}</a>
<div ng-view></div>

In my module config

  $routeProvider.
  when('/', {
    controller:HomeCtrl,
    templateUrl:'home.html'
  }).
  when('/menu', {
    controller:MenuCtrl,
    templateUrl:'menu.html'
  }).
  when('/items', {
    controller:ItemsCtrl,
    templateUrl:'items.html'
  }).
  otherwise({
    redirectto:'/'
  });

Controllers

function HomeCtrl($scope, $rootScope){
  $rootScope.header = "Home";
  $rootScope.back = {url:'#/menu', text:'Menu'};
}

function MenuCtrl($scope, $rootScope){
  $rootScope.header = "Menu";
  $rootScope.back = {url:'#/', text:'Back'};
}

function ItemsCtrl($scope, $rootScope){
  $rootScope.header = "Items";
  $rootScope.back = {url:'#/', text:'Back'};
}

As you can see in my controllers I have hard coded the back button url and text (Actually I don't need the text as using an image). In this way I found back button navigate incorrectly in some cases. I cannot use history.back() coz my back button changes to a menu link in home view.

So my question is how do I get the previous route path in controllers or is better way to achieve this ?

I have created a Plunker demonstration of my problem. Please check that.

Gihan
  • 4,163
  • 6
  • 31
  • 49
  • Why do you need to manually handle back button navigation when AngularJS provides deep linking/back button functionality by default (example: http://wordcharconvertor.rogtopia.com/)? – Stewie Mar 02 '13 at 14:51
  • @stewie Sorry I'm newbie to angularjs and I didn't quite get what you mean. Could you please provide better example with better explanation? Please note my back link navigation's behavior is little different than browser's back button – Gihan Mar 02 '13 at 15:11
  • You should follow @MarkRajcok answer. – Stewie Mar 03 '13 at 01:00
  • 1
    I was going to upvote this, but you didn't mark @andersh's answer. – mellis481 Nov 12 '15 at 19:51

8 Answers8

74

This alternative also provides a back function.

The template:

<a ng-click='back()'>Back</a>

The module:

myModule.run(function ($rootScope, $location) {

    var history = [];

    $rootScope.$on('$routeChangeSuccess', function() {
        history.push($location.$$path);
    });

    $rootScope.back = function () {
        var prevUrl = history.length > 1 ? history.splice(-2)[0] : "/";
        $location.path(prevUrl);
    };

});
andersh
  • 8,105
  • 6
  • 39
  • 30
  • 1
    Btw, I don' think you need to use $location, as the $routeChangeSucces callback is called with two parameters: current, next. http://docs.angularjs.org/api/ngRoute.$route – Kenneth Lynne Nov 22 '13 at 13:52
  • 2
    @KennethLynne I tried to use the `current.$$route.originalPath` instead of `$location.$$path` but the route parameters were only filled in when using `$location`. If you don't use route params then your suggestion should work. – Austin Thompson Mar 18 '14 at 16:51
  • It should use with local storage for persistency. Otherwise history will be vanished if the page refreshed. – Gihan Feb 12 '16 at 04:33
  • You are storing in rootscope , but when page refreshes(when user enters ctrl+ F5) it will disappear right?? So where to store that back function ???? – sudhir Apr 19 '16 at 09:21
  • Yes @sudhir, the history does not survive page refresh, if you need to persist it you should probably use local storage to store the history array. – andersh Apr 19 '16 at 11:59
22

Use the $locationChangeStart or $locationChangeSuccess events, 3rd parameter:

$scope.$on('$locationChangeStart',function(evt, absNewUrl, absOldUrl) {
   console.log('start', evt, absNewUrl, absOldUrl);
});
$scope.$on('$locationChangeSuccess',function(evt, absNewUrl, absOldUrl) {
   console.log('success', evt, absNewUrl, absOldUrl);
});
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • 2
    Thanks @ArturBodera, I see they are now documented here: http://docs.angularjs.org/api/ng.$location#events I updated the answer. – Mark Rajcok Dec 09 '13 at 16:17
  • This saved my day... I had a problem of not reloading the controller, when one of the `$routeParams` changed due to user operating "back" and "forward" buttons in the browser. With these events I can catch this navigation. – Liglo App Dec 02 '14 at 14:06
19

In your html :

<a href="javascript:void(0);" ng-click="go_back()">Go Back</a>

On your main controller :

$scope.go_back = function() { 
  $window.history.back();
};

When user click on Go Back link the controller function is called and it will go back to previous route.

Afshin Mehrabani
  • 33,262
  • 29
  • 136
  • 201
Mohd Jafar
  • 291
  • 3
  • 9
  • In my case, I did not need the `$`, I just used `window.history.back();` – App Dev Guy Jun 16 '16 at 03:27
  • 3
    @AppDevGuy `$window` is an angular wrapper for `window`, and you're encouraged to use it instead of `window`, because this way it can be mocked for testing etc. From angular docs (https://docs.angularjs.org/api/ng/service/$window): "In angular we always refer to it [to `window`] through the $window service, so it may be overridden, removed or mocked for testing." – DarthVanger Jan 13 '17 at 16:45
5

@andresh For me locationChangeSuccess worked instead of routeChangeSuccess.

//Go back to the previous stage with this back() call
var history = [];
$rootScope.$on('$locationChangeSuccess', function() {
    history.push($location.$$path);
});

$rootScope.back = function () {
          var prevUrl = history.length > 1 ? history.splice(-2)[0] : "/";
          $location.path(prevUrl);
          history = []; //Delete history array after going back
      };
Shahid
  • 87
  • 2
  • 4
4

This is how I currently store a reference to the previous path in the $rootScope:

run(['$rootScope', function($rootScope) {
        $rootScope.$on('$locationChangeStart', function() {
            $rootScope.previousPage = location.pathname;
        });
}]);
daveoncode
  • 18,900
  • 15
  • 104
  • 159
4

You'll need to couple the event listener to $rootScope in Angular 1.x, but you should probably future proof your code a bit by not storing the value of the previous location on $rootScope. A better place to store the value would be a service:

var app = angular.module('myApp', [])
.service('locationHistoryService', function(){
    return {
        previousLocation: null,

        store: function(location){
            this.previousLocation = location;
        },

        get: function(){
            return this.previousLocation;
        }
})
.run(['$rootScope', 'locationHistoryService', function($location, locationHistoryService){
    $rootScope.$on('$locationChangeSuccess', function(e, newLocation, oldLocation){
        locationHistoryService.store(oldLocation);
    });
}]);
Trendy
  • 460
  • 2
  • 12
1

Just to document:

The callback argument previousRoute is having a property called $route which is much similar to the $route service. Unfortunately currentRoute argument, is not having much information about the current route.

To overcome this i have tried some thing like this.

$routeProvider.
   when('/', {
    controller:...,
    templateUrl:'...',
    routeName:"Home"
  }).
  when('/menu', {
    controller:...,
    templateUrl:'...',
    routeName:"Site Menu"
  })

Please note that in the above routes config a custom property called routeName is added.

app.run(function($rootScope, $route){
    //Bind the `$routeChangeSuccess` event on the rootScope, so that we dont need to 
    //bind in induvidual controllers.
    $rootScope.$on('$routeChangeSuccess', function(currentRoute, previousRoute) {
        //This will give the custom property that we have defined while configuring the routes.
        console.log($route.current.routeName)
    })
})
Rajkamal Subramanian
  • 6,884
  • 4
  • 52
  • 69
  • I'm getting the log in the console, but I still don't see how to go back in history. I think I've hit a bug in Angular with this issue: http://stackoverflow.com/questions/17712735/cant-stay-on-same-page-route-after-closing-modal-window-in-angular-js-on-ipad?noredirect=1#comment25816387_17712735 – Paul Jul 19 '13 at 04:41
1

modification for the code above:

$scope.$on('$locationChangeStart',function(evt, absNewUrl, absOldUrl) {
   console.log('prev path: ' + absOldUrl.$$route.originalPath);
});
danikoren
  • 4,191
  • 7
  • 34
  • 33