Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular. How to make CanDeactivate work correctly with the use of Location.back()

I'm implementing CanDeactivate functionality in one of my main components. To test it I've made it to always return false so the route must not change.

This is the CanDeactivate implementation in which the call to component.canDeactivate() returns a Promise resolved to false:

@Injectable()
export class CanDeactivateNewRecord implements 
CanDeactivate<NewRecordComponent> {
    canDeactivate(
        component: NewRecordComponent,
        currentRoute: ActivatedRouteSnapshot,
        currentState: RouterStateSnapshot,
        nextState: RouterStateSnapshot ): 
        Observable<boolean>|Promise<boolean>|boolean {

        return component.canDeactivate();
    }
}

This is the fragment with definition of the routes for the module:

const recordsRoutes: Routes = [
    {
        path: 'nou',
        component: NewRecordComponent,
        canDeactivate: [CanDeactivateNewRecord]
    },{
        path: ':id',
        component: RecordComponent
    }
];

When I use the method back of the service Location from @angular/common to navigate to a previous page there are two different situations:

  • if the previous location was managed by the Angular router the navigation is prevented and the application stay at the route of this component,
  • if the previous location was outside the application (for example if the url of the route for this component was introduced directly in the browser navigation bar) it goes outside the applicatin and loads the previous page.

Even if the previous location was managed by the router, calling location.back() enough times (as many times as the length of the history of navigation through the application) it makes the navigation return to the page before the start of the application.

What's wrong with this?

like image 278
francadaval Avatar asked May 17 '17 16:05

francadaval


1 Answers

I know this is SUPER late, but I had this exact same issue and figured I'd leave this here for posterity. As another stated, it is a known Angular issue that has yet to be fixed. There is a workaround that I was able to make use of, it can be found here: github

Implementation for your code would look something like this:

@Injectable()
export class CanDeactivateNewRecord implements CanDeactivate<NewRecordComponent> {
    constructor(
        private readonly location: Location;
        private readonly router: Router;
    ){}
    canDeactivate(component: NewRecordComponent, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot ): Observable<boolean>|Promise<boolean>|boolean {
        if(component.canDeactivate()){
            return true
        }else{
            const currentUrlTree = this.router.createUrlTree([], currentRoute);
            const currentUrl = currentUrlTree.toString();
            this.location.go(currentUrl)
            return false
        }
    }
}

Grabs the most recent route and inserts back into the url tree if canDeactivate returns false.

like image 59
Rharris389 Avatar answered Sep 21 '22 12:09

Rharris389