Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at the New York ColdFusion User Group (Dec. 2008) with: Clark Valberg and Michael Dinowitz
Ben Nadel at the New York ColdFusion User Group (Dec. 2008) with: Clark Valberg@clarkvalberg ) and Michael Dinowitz@mdinowitz )

$route redirectTo Does Not Break The Back Button In AngularJS

By Ben Nadel on

When defining routes in an AngularJS application, you can provide routes that do nothing but redirect to other routes. This works for both explicitly defined routes as well as for the catch-all "otherwise" route. One awesome feature of the "redirectTo" property, which I just discovered, is that it will not break the browser's back-button.


 
 
 

 
 
 
 
 

Run this demo in my JavaScript Demos project on GitHub.

Under the hood, the redirectTo action is implemented using the $location.replace() method. This method is used to replace the current location rather than pushing a new location onto the history stack. By not adding to the history stack, AngularJS allows the browser's back-button to circumvent the current location.

To see this in action, I've created a tiny $route demo that contains two "redirectTo" route configurations:

  • /people => /people/friends
  • "catch all" => /home

The first one allows the application to link users to a general section [people] without having to be overly specific. The second simply catches any missing route and redirects the user back to the homepage.

The important thing to know (which you can't see from the code itself) is that after the "redirectTo" is executed, the user's back and forward buttons (on their browser) jump over the redirect entirely.

  • <!doctype html>
  • <html ng-app="Demo">
  • <head>
  • <meta charset="utf-8" />
  •  
  • <title>
  • $route redirectTo Does Not Break The Back Button In AngularJS
  • </title>
  • </head>
  • <body ng-controller="AppController">
  •  
  • <h1>
  • $route redirectTo Does Not Break The Back Button In AngularJS
  • </h1>
  •  
  • <p>
  • <a href="#/home">Home</a>
  • &mdash;
  • <a href="#/people">People</a>
  • &mdash;
  • <a href="#/broken">Broken link</a>
  • </p>
  •  
  • <p>
  • <strong>Action</strong>: {{ routeAction }}
  • </p>
  •  
  •  
  • <!-- Load scripts. -->
  • <script type="text/javascript" src="../../vendor/angularjs/angular-1.3.8.min.js"></script>
  • <script type="text/javascript" src="../../vendor/angularjs/angular-route-1.3.8.min.js"></script>
  • <script type="text/javascript">
  •  
  • // Create an application module for our demo.
  • var app = angular.module( "Demo", [ "ngRoute" ] );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // I setup the routes for the application.
  • app.config(
  • function( $routeProvider ) {
  •  
  • $routeProvider
  • .when(
  • "/home",
  • {
  • action: "home"
  • }
  • )
  •  
  • // Notice that this route doesn't actually map to an action. Rather,
  • // it redirects to a sub-route off of the current route.
  • // --
  • // NOTE: Under the hood, this uses $location.replace(), which is
  • // intended to keep the back-button working properly with redirects.
  • .when(
  • "/people",
  • {
  • redirectTo: "/people/friends"
  • }
  • )
  •  
  • .when(
  • "/people/friends",
  • {
  • action: "people.friends"
  • }
  • )
  • .when(
  • "/people/enemies",
  • {
  • action: "people.enemies"
  • }
  • )
  • .otherwise({
  • redirectTo: "/home"
  • })
  • ;
  •  
  • }
  • );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // I control the root of the application.
  • app.controller(
  • "AppController",
  • function( $scope, $route, $routeParams ) {
  •  
  • $scope.routeAction = null;
  •  
  • // I listen for route-change events.
  • $scope.$on(
  • "$routeChangeSuccess",
  • function handleRouteChangeEvent( event ) {
  •  
  • var current = $route.current;
  •  
  • console.log( "Route change event:", current.originalPath );
  •  
  • // If the current route doesn't contain an action, then it will,
  • // in all likelihood, be redirected to another route that does
  • // contain a valid action (configured in $routeProvider).
  • if ( ! current.action ) {
  •  
  • console.warn(
  • "Route does not contain an action.",
  • "Redirecting to another route."
  • );
  •  
  • }
  •  
  • // Store our current action for output.
  • $scope.routeAction = current.action;
  •  
  • }
  • );
  •  
  • }
  • );
  •  
  • </script>
  •  
  • </body>
  • </html>

Since the point of this demo is to showcase browser behavior (and the AngularJS integration), the output is not immediately obvious. As such, I suggest watching the video or trying out the demo.


 
 
 

 
 redirectTo does not break the back button in an AngularJS application. 
 
 
 

In any case, it's awesome that this is how AngularJS implemented the redirectTo feature. I wish I had known about this earlier - I have put way too much redirect logic into my Controllers when it could have been easily handled in the route itself.




Reader Comments

Hi,
I have a single page angularapp.
In the home page : http://localhost:8080/APPNAME/#/home.
When user selects a radio button,

The link is http://localhost:8080/APPNAME/#/xxxx/Multiple. Here the user makes multiple selections and clicks "SUBMIT".

We display the results, still the URL is
http://localhost:8080/APPNAME/#/xxxx/Multiple.

From here when the user clicks browser back button, the app is going to
'http://localhost:8080/APPNAME/#/home'
But I want to stay at http://localhost:8080/APPNAME/#/xxxx/Multiple.

How to detect if user pressed browser back button in Angualrjs.

Reply to this Comment

Hi,
Awesome post, I want to know can we do the same,If i am using component router in my app(Angular version 1.5.x)

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.