Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS redirect without pushing a history state

I'm working on an AngularJS app that has a catch all route (eg, .when('/:slug', {...)) which is necessary to support legacy url formats from a previous (non-angular) version of the app. The controller that responds to the catch all tries pulling a related object, and, if not found, redirects to a 404 page using the $location.path method. This works at getting the user to the 404 page, but when the user hits back in their browser it takes them back to the page that forced them to the 404 page in the first place and they end up being unable to escape the cycle.

My question is if there is 1) a better pattern for handling this situation, or 2) if there is a way to reroute the user that doesn't force a history push state in the browser?

like image 1000
kyleder Avatar asked Sep 25 '13 18:09

kyleder


People also ask

How do I redirect a route in angular?

Implement routing by importing ‘Router’ from ‘@angular/router’. Then initialize the router in the constructor. After doing the above process, then implement routing in a function so that the function can be triggered from .html file. Once everything is done then we can force redirect the route to another component.

What is the use of state object in angular router?

The state object is a very handy addition to the extremely powerful Angular’s Router. I’ve been in need of passing some data during navigation in the following situations: navigation to the error page with an error’s code, so that a proper message could be obtained based on a code-message dictionary.

Should state be kept when navigating between components in angular?

I recently had to redirect between some components in an Angular application and I figured it would be a better user experience if the state was kept when navigating. So if you went back to the previous component you would be presented with the component as you left it.

How to get initial state of a reducer in angular?

We have initial state in each reducer as below you need to populate the initial state from storage by reading the appropriate keys NGRX Store and the library ngrx-store-localstorage makes it easy to retrieve the state when you refresh the page. You have to be careful when designing the Angular app for the page refresh scenarios.


Video Answer


2 Answers

You can change the url without adding to the history state, found here under "Replace Method". This is effectively the same as calling HTML5's history.replaceState().

$location.path('/someNewPath').replace();

I haven't found that it's possible to change the view without changing the url. The only method to change the view, that I've found, is to change the location path.

like image 150
thrashr888 Avatar answered Oct 12 '22 03:10

thrashr888


The normal operation of the route system is for the $route service to watch for the $locationChangeSuccess event and then begin loading a route. When it's done loading the template, performing the resolve steps and instantiating the controller it then in turn broadcasts a $routeChangeSuccess event. That $routeChangeSuccess is monitored by the ng-view directive, and that's how it knows to swap out the templates and scopes once the new route is ready.

With all of the above said, it may work to have application code emulate the behavior of the $route service by updating the current route and emitting the route change event to get the view to update:

var errorRoute = $route.routes[null]; // assuming the "otherwise" route is the 404
// a route instance is an object that inherits from the route and adds
// new properties representing the routeParams and locals.
var errorRouteInstance = angular.inherit(
    errorRoute,
    {
        params: {},
        pathParams: {},
    }
);
// The $route service depends on this being set so it can recover the route
// for a given route instance.
errorRouteInstance.$$route = errorRoute;

var last = $route.current;
$route.current = errorRouteInstance;

// the ng-view code doesn't actually care about the parameters here,
// since it goes straight to $route.current, but we should include
// them anyway since other code might be listening for this event
// and depending on these params to behave as documented.
$rootScope.broadcast('$routeChangeSuccess', errorRoute, last);

The above assumes that your "otherwise" route doesn't have any "resolve" steps. It also assumes that it doesn't expect any $routeParams, which is of course true for the "otherwise" route but might not be true if you use a different route.

It's unclear what of the above is depending on implementation details vs. interface. The $routeChangeSuccess event is certainly documented, but the $$route property of the route instance seems to be an implementation detail of the route system given its double-dollar-sign name. The detail that the "otherwise" route is kept in the route table with the key null is possibly also an implementation detail. So with all of this said, this behavior may not remain functional in future versions of AngularJS.

For more information you could refer to the ng-view code that handles this event, which is ultimately what the above code is trying to please, along with the event emitting code that I used as the basis for the above example. As you could infer from these links, the information in this post is derived from the latest master branch of AngularJS, which at the time of writing is labelled as 1.2.0-snapshot.

like image 38
Martin Atkins Avatar answered Oct 12 '22 04:10

Martin Atkins