New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Router 3.2.0 - canDeactivate runs only once #12851
Comments
closing as submitter deleted/ignored the provided issue template and did not provide a reproduction. i'll re-open if this changes. |
Here's my code. Guard:
Dialog component (the one used above):
Routes:
and the module:
So, again, the standard scenario - user edits a form, clicks on Cancel, canDeactivate works the first time (suppose user wishes to stay on the form). He edits the form and tries to leave it again => this time canDeactivate doesn't work in 3.2.0-rc.0. But works on 3.1.0. |
Please provide a Plunker. |
Guys, I'm not really sure I'm that familiar with plunkr. Can I publish a repo on GitHub? Is it ok? BTW, just checked with router 3.2.0 - problem is still there. |
Edit: since guys know better than me how to provide a plunker, my repo and app are deleted.ok, here's my repo - https://github.com/alvipeo/ng2router-test . and the app running here - http://ng-2.azurewebsites.net/. You'll find step on how to repro on the main page. The guard is implemented here - https://github.com/alvipeo/ng2router-test/blob/master/src/app/features/subscribers/saveChangesGuard.ts. It has console.log(component) inside canDeactivate. So if it really fires, you should see an output in the console. The routing - https://github.com/alvipeo/ng2router-test/blob/master/src/app/features/subscribers/subscribers.routing.ts. Hopefully, this helps. |
I actually encounted similar bug with Issue is that when guard resolves to false value it is not being called anymore. Here is plunker with Here is plunker with |
In my application, I notice that the guard is not called a second time if you try to follow the same route as before. It does not even try to to execute the same route a second time. If you try to follow another route, the guard is called. |
Let me explain the scenario more precisely. (1) first I route to A But if try to route to C instead of B in step (3) or after step (3), the CanDeActivate check on A is performed. |
@DzmitryShylovich so what? how is this related to this bug? just didn't get it |
You are right, the following piece of code causes these kind of issues
After this piece of code, the new navigation is added to the scheduled navigations "queue". |
I am encountering this exact scenario. I haven't broken it down into a plunker yet, but basically it looks like a promise that resolves to false inside a canDeactivate guard only runs once. It seems that if the guard just returns a boolean, all is fine. |
I have the same problem, canDeactivate guard runs only once. However the issue also exists in the Tour of Heros live example so I think any additional plunkr is not really necessary. |
I have the same issu in my code but in my understanding it is not specifically related to the gards but to the navigation scheduling. in addition to @Krustie101 comment, this part of the code is also related:
Should this behaviour only occure when navigation is triggered from browser back button ? |
I ended up here because of this Stack Overflow article: http://stackoverflow.com/questions/40692497/calling-angular2-route-guard-multiple-times/40693108 This is a serious issue as it brakes people's authentication systems. |
There is one walkaround you can use. Just before you return false on your CanActivate, force to navigate where you came from :
This will force the last navigation in the router history not to be the one that you just canceled and therefore the router will actually try again to navigate as expected. |
No workaround for CanDeactivate though.. |
This plunkr demonstrates the issue: Click 'Guarded Component Two', dismiss the alert, and then click it again. Notice no alert is shown. This plunkr is the same except the router is reverted to version 3.1.2: Follow the same steps and notice you get an alert every time you click the link. |
@eeubank perfect demonstration here is the workaround for CanActivate: http://plnkr.co/edit/fxpouRAdOyUOp4CpjW1u?p=preview edit: it also works for CanDeactivate: http://plnkr.co/edit/olw4z85aBXenJhFawi5G?p=preview |
Similar to @Adboul's workaround for CanActivate, CanDeactivate can be worked around also by using RouteStateSnapshot: http://plnkr.co/edit/6BC3IE5t9CELDtYLbaTt?p=preview
|
Glad I searched the issue tracker - this has been driving me nuts for hours. Having the same problem, and also traced it via breakpoints to the Just saw previous comment - looks like there is an easy way to get the previous/next route info. Good to know! |
The Deactivate workaround doesn't seem to work in my case, I return the response of a prompt dialog via a Observable instead of just boolean. |
@Falx |
In your plunkr, my Observable would be returned by the component.canDeactivate(); function. (since that will throw up a Dialog for the user to click if he has unsaved changes) Or.. Am I doing it wrong? edit: Seems I am getting somewhere now, only my prompt dialog is getting fired twice, but that is probably a mistake in my own code |
@Falx seems to work that way: |
@Adboul Thanks a lot man, I got it working thanks to you! |
Unfortunately after some messing around this morning, I haven't found a way to fix this without breaking a bunch of unit tests. My initial attempt, which does fix this problem, is a patch to the
Basically, if navigation fails, then restore the previous navigation. However, as I said, this breaks several other unit tests, so I'm sure this is not the right solution. It causes more events to be triggered than expected, which is because I'm basically creating a new navigation event. It may need to be more complicated than this. I also tried keeping a string member variable of the previous URL and using that for the comparison, but that seems to also break a bunch of tests. |
@brendanbates89 I think that your attempt kind of break the logic of the router. A rejected navigation attempt is still a navigation attempt and should be kept as the last navigation. Also, anybody who subscribe to navigations would think that a new navigation was fired which is not the case. I think that a solution could be to keep track of a resolved/reject navigation and return the current navigation promise if the it's not pending. Something like that:
(I know isPending is not a promise property, I wrote that for the logic) |
@Adboul Yeah, that's what I figured, I had a feeling that really wasn't the proper solution. The real issue here is that the current value in |
@brendanbates89 no worries I am in the exact same situation as you are :) |
Just to note, there is another side effect to this as well. If you are on Page A navigating to Page B, and the guard returns It definitely has to do with the fact that |
i have the same issue.... |
Yes! Thank you guys! |
Hello guys. Is this fix available on the npm repository? Ie, if i do a npm install for the router package, does it include the fix? |
@luisabreu yes, if you check the changelog you'll see that the fix for this issue landed with 2.3.0
|
Had the same problem and realized it was because i was return a promise. I changed it to an observable and it was fixed... |
Somehow I've managed this to working with
right before you return false in CanDeactivate it'll restore the state again so back button will be detected.
just call this when landing on a page in constructor of any service and it will add a state before your current state. let me know if there is any decent solution present :( |
My Workaround to keep exact same state than before back click using canDeactivate:
|
I am using angular router version 4.4.4 and canDeactivate function is not working for me. |
sorry, that was mine issue |
I am using angular router version 5.2.2 and canDeactivate will change history when I use |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
let's say you have a confirmation dialog on canDeactivate. if user refuses to leave a form (clicks No), the dialog closes (promise is resolved to false). now, user does the same thing again but canDeactivate doesn't fire anymore.
This doesn't happen on 3.1.0.
The text was updated successfully, but these errors were encountered: