Here is the set up:
A user is on the page “A”. There is a dropdown (DROPDOWN) used for navigation.
There are 2 options user can pick from: A, B. Where A represents the current page and B is something the user wants to go to.
This dropdown is bound to a dependent observable (GUARD) which can read and may or may NOT write to another regular observable (TARGET) that holds the state of that dropdown.
DROPDOWN <– –> GUARD <– ?–> TARGET
The idea is that if the user picks something in the dropdown to navigate away from the page first we check if there are any unsaved changes and if there are, we ask the user whether he wants to discard them or stay on the page and continue editing.
So the situation:
There are unsaved changes. The user picks something from the dropdown. The GUARD kicks in by getting its ‘write’ method called. We prompt the user if he wants to discard changes and navigate off the page or stay. The user chooses to stay. We say ‘fine’ and the write method doesn’t do anything, so the target observable stays intact. End of story! But..
As the user touched the dropdown and the ‘change’ even wasn’t cancelled (there are no means for doing it inside a bound observable) the drop down got to state “B” as if the user chose to navigated off the page.
So my question is simple:
-
Is there a way to cancel the ‘change’ event from withing the ‘write’ method of the dependent observable the dropdown is bound to?
-
If no, how do I get out of this situation keeping the selection of the dropdown in sync with the TARGET observable?
The ‘change’ event occurs after the dropdown has already changed, so a simple solution would be to cause the dropdown to “refresh” using the old value, easily done with a call to
target.valueHasMutated().Example fiddle: http://jsfiddle.net/KXhem/77/
Edit: Since knockout 3, computed’s only notify if their value has really changed. To get the same behavior you can add
.extend({ notify: 'always' })to the computed.See the full details here: http://knockoutjs.com/upgrade-notes/v3.0.0.html