PaulBunion
PaulBunion

Reputation: 405

Angular Route Guard stay on page after refresh

My main page has a set of items, from which the user can click on an item, which will bring them to an item details page. From either that main page, or the details page, the user should be able to navigate to a third page with a form specific to that item.

I have set up a router guard to prevent the user from navigating to this form page if the origin was not one of the two pages previous pages. If attempting to navigate to the form page from an invalid location, the user will be routed to the main page. My router guard largely works, but if refreshing the page from the form page, the user is kicked back to the main page, which is not ideal. How can I have my routing guard ignore page refreshes if the user was already on the protected form page?

routing.guard.ts

class RoutingGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(): boolean | Promise<boolean> {
    const currentUrl = this.router.url;
    // The slice()s chop off the item ID so I can check the base url.
    // Otherwise it'll mangle the url, which will fail the checks below
    // and we'll end up with the default navigation, as desired.
    const detailsUrl = currentUrl.slice(0, 20);
    const formUrl = currentUrl.slice(0, 19);

    // These checks (should) only allow access to the form page if
    // coming from the details page or the main page (or, in theory
    // the form page itself)
    if(detailsUrl === '/main/details') return true;
    // this is what doesn't work, because naturally the page refresh
    // wipes out the url
    if(formUrl === '/main/form') return true;
    if(currentUrl === '/main') return true;

    // Default: send the user back to the main page
    return this.router.navigateByUrl('/main');
  }
}

The routes in routing.module.ts

const routes: Routes = [
  {
    path: 'main',
    component: MainComponent,
  },
  {
    path: 'details/:id',
    component: DetailsComponent,
  },
  {
    path: 'form/:id',
    component: FormComponent,
    canActivate: [RoutingGuard],
  },
];

Upvotes: 2

Views: 2655

Answers (1)

Joosep Parts
Joosep Parts

Reputation: 6245

Previous url can't be caught with router. After refresh all data is flushed. You'd have to store the data outside of Angular to save it (e.g sessionStorage) to get get. However, your issue is that after refresh you still should be able to read currentUrl. My guess it that slicing doesn't quite do what you expect it to. I think you're slicing a bit too much. Check what is that sliced content. Instead of using === compare operator try to use if(detailsUrl.includes('details')) return true; etc.

With router

previousUrl: string;
constructor(router: Router) {
  router.events
  .pipe(filter(event => event instanceof NavigationEnd))
  .subscribe((event: NavigationEnd) => {
    console.log('prev:', event.url);
    this.previousUrl = event.url;
  });
}

Here is a example: https://stackblitz.com/edit/angular-getting-previous-url-8ba1dh?file=src%2Fapp%2Fapp.component.ts

Upvotes: 1

Related Questions