Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
AngularJS directive to create a functional "back" button
app.directive('backButton', function(){
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', goBack);
function goBack() {
history.back();
scope.$apply();
}
}
}
});
<a href back-button>back</a>
@tesnep

This comment has been minimized.

Show comment Hide comment
@tesnep

tesnep Sep 19, 2013

I am not sure I follow this. In a single page app, pressing the back button should take you to other "theoretical-pages" like Home, About Us, etc within the single-page app. What this does is take us back to previous window.href.

tesnep commented Sep 19, 2013

I am not sure I follow this. In a single page app, pressing the back button should take you to other "theoretical-pages" like Home, About Us, etc within the single-page app. What this does is take us back to previous window.href.

@gwendall

This comment has been minimized.

Show comment Hide comment
@gwendall

gwendall Oct 9, 2013

The problem here is that if the previous state is on another website, the user should not be redirected there. A solution is to track whether or not the user has a previous state within your Angular-powered app to decide whether or not to call history.back().

The way I implemented it was by tracking if the state changed within rootScope:

$rootScope.navigated = false;
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
    if (from.name) { $rootScope.navigated = true; }
}); 

Then you can evaluate it in your directive:

function goBack() {
if (scope.navigated) {
history.back();
scope.$apply();
}
}

gwendall commented Oct 9, 2013

The problem here is that if the previous state is on another website, the user should not be redirected there. A solution is to track whether or not the user has a previous state within your Angular-powered app to decide whether or not to call history.back().

The way I implemented it was by tracking if the state changed within rootScope:

$rootScope.navigated = false;
$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
    if (from.name) { $rootScope.navigated = true; }
}); 

Then you can evaluate it in your directive:

function goBack() {
if (scope.navigated) {
history.back();
scope.$apply();
}
}

@robsonximenes

This comment has been minimized.

Show comment Hide comment
@robsonximenes

robsonximenes Feb 19, 2014

Is there a way to back with the old state?

Is there a way to back with the old state?

@frenchtoast747

This comment has been minimized.

Show comment Hide comment
@frenchtoast747

frenchtoast747 Jul 13, 2014

I would suggest changing the call to history.back(); to $window.history.back(); thus making it easier for unit testing and removing the need for the call to scope.$apply(). Something like my fork.

I would suggest changing the call to history.back(); to $window.history.back(); thus making it easier for unit testing and removing the need for the call to scope.$apply(). Something like my fork.

@edbentinck

This comment has been minimized.

Show comment Hide comment
@edbentinck

edbentinck Jul 22, 2014

@frenchtoast747 - Your suggestion is a good one, thanks. However, be careful – your fork has a few mistakes. Your directive isn't returning anything, and it's missing a ] towards the end.

It should read more along the lines of the following:

app.directive('backButton', ['$window', function($window) {
        return {
            restrict: 'A',
            link: function (scope, elem, attrs) {
                elem.bind('click', function () {
                    $window.history.back();
                });
            }
        };
    }]);

@frenchtoast747 - Your suggestion is a good one, thanks. However, be careful – your fork has a few mistakes. Your directive isn't returning anything, and it's missing a ] towards the end.

It should read more along the lines of the following:

app.directive('backButton', ['$window', function($window) {
        return {
            restrict: 'A',
            link: function (scope, elem, attrs) {
                elem.bind('click', function () {
                    $window.history.back();
                });
            }
        };
    }]);
@n3ssi3

This comment has been minimized.

Show comment Hide comment
@n3ssi3

n3ssi3 Aug 22, 2014

Hi, Is there also a nice way to hide the backButton when you actually can not go back any further?

n3ssi3 commented Aug 22, 2014

Hi, Is there also a nice way to hide the backButton when you actually can not go back any further?

@kyleledbetter

This comment has been minimized.

Show comment Hide comment
@kyleledbetter

kyleledbetter Feb 2, 2015

Thx @edbentinck your code works great for me.

@n3ssi3 if you're using ui-router you can do something like this to hide the button on the homepage:

ng-class="{'ng-hide':$state.is('home')}"

Substiture that state.is('home') for whatever you like

Thx @edbentinck your code works great for me.

@n3ssi3 if you're using ui-router you can do something like this to hide the button on the homepage:

ng-class="{'ng-hide':$state.is('home')}"

Substiture that state.is('home') for whatever you like

@sterichards

This comment has been minimized.

Show comment Hide comment
@sterichards

sterichards Aug 5, 2015

This works great.

Thanks!

This works great.

Thanks!

@maxialoise

This comment has been minimized.

Show comment Hide comment
@maxialoise

maxialoise Aug 30, 2016

Thanks!!

Thanks!!

@Tarunkumar0

This comment has been minimized.

Show comment Hide comment
@Tarunkumar0

Tarunkumar0 Nov 20, 2017

But Back button still displayed in Main page. How to hide it

But Back button still displayed in Main page. How to hide it

@marie-dk

This comment has been minimized.

Show comment Hide comment
@marie-dk

marie-dk Nov 22, 2017

Why not use something like $localStorage (ngStorage) to save the previous state. That way it is preserved on reload.

In the run block...
Initialize storage

$localStorage.$default({
  prevState:{}
});

Save previous state on state change:

$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
    if (from.name) { 
      $localStorage.prevState = {'state':from,'params':fromParams}; 
    }
}); 

In the directive
Check storage for previous navigation and simply use state.go with the values from storage. I would probably also have a default page to go to, just in case...

angular.module("directive.backbutton",[])

.directive("backButton", ['$state','$localStorage', function ($state,$localStorage) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind('click', goBack);
      function goBack() {
        if ($localStorage.prevState.state !== undefined) {
          $state.go($localStorage.prevState.state,$localStorage.prevState.params);
        } 
      }
    }
  }
}]);

Why not use something like $localStorage (ngStorage) to save the previous state. That way it is preserved on reload.

In the run block...
Initialize storage

$localStorage.$default({
  prevState:{}
});

Save previous state on state change:

$rootScope.$on('$stateChangeSuccess', function (ev, to, toParams, from, fromParams) {
    if (from.name) { 
      $localStorage.prevState = {'state':from,'params':fromParams}; 
    }
}); 

In the directive
Check storage for previous navigation and simply use state.go with the values from storage. I would probably also have a default page to go to, just in case...

angular.module("directive.backbutton",[])

.directive("backButton", ['$state','$localStorage', function ($state,$localStorage) {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      element.bind('click', goBack);
      function goBack() {
        if ($localStorage.prevState.state !== undefined) {
          $state.go($localStorage.prevState.state,$localStorage.prevState.params);
        } 
      }
    }
  }
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment