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

4
  • Why do you need to manually handle back button navigation when AngularJS provides deep linking/back button functionality by default (example: wordcharconvertor.rogtopia.com)? Commented Mar 2, 2013 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 Commented Mar 2, 2013 at 15:11
  • You should follow @MarkRajcok answer. Commented Mar 3, 2013 at 1:00
  • 1
    I was going to upvote this, but you didn't mark @andersh's answer. Commented Nov 12, 2015 at 19:51

8 Answers 8

73

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

});
Sign up to request clarification or add additional context in comments.

5 Comments

Btw, I don' think you need to use $location, as the $routeChangeSucces callback is called with two parameters: current, next. docs.angularjs.org/api/ngRoute.$route
@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.
It should use with local storage for persistency. Otherwise history will be vanished if the page refreshed.
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 ????
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.
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);
});

2 Comments

Thanks @ArturBodera, I see they are now documented here: docs.angularjs.org/api/ng.$location#events I updated the answer.
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.
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.

2 Comments

In my case, I did not need the $, I just used window.history.back();
@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 (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."
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
      };

Comments

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

Comments

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

1 Comment

smart solution is the goal is save url globally, otherwise for single cases @MarkRajcok solution is a good way
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)
    })
})

1 Comment

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: stackoverflow.com/questions/17712735/…
1

modification for the code above:

$scope.$on('$locationChangeStart',function(evt, absNewUrl, absOldUrl) {
   console.log('prev path: ' + absOldUrl.$$route.originalPath);
});

3 Comments

That modification does not work if you are using route parameters. The parameters are not filled in for originalPath
$scope.on causes an error '$scope.on is not a function.' I think you use $scope.$on instead.
The param absOldUrl is the prev URL.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.