-
Notifications
You must be signed in to change notification settings - Fork 107
Warn before leaving recipe editor with changes #464
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
Changes from 3 commits
0597035
d3a843f
3d12202
7feb1b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -60,7 +60,13 @@ export default { | |
| // keep it up to date in multiple places if it changes later | ||
| recipeInit: null, | ||
|
|
||
| // ========================== | ||
| // These are helper variables | ||
|
|
||
| // Changes have been made to the initial values of the form | ||
| formDirty: false, | ||
| // the save button has been clicked | ||
| savingRecipe: false, | ||
| prepTime: { time: [0, 0], paddedTime: '' }, | ||
| cookTime: { time: [0, 0], paddedTime: '' }, | ||
| totalTime: { time: [0, 0], paddedTime: '' }, | ||
|
|
@@ -109,6 +115,12 @@ export default { | |
| // convert keyword array to comma-separated string | ||
| this.recipe['keywords'] = this.selectedKeywords.join() | ||
| } | ||
| }, | ||
| recipe: { | ||
| deep: true, | ||
| handler() { | ||
| this.formDirty = true | ||
| } | ||
| } | ||
| }, | ||
| methods: { | ||
|
|
@@ -129,6 +141,19 @@ export default { | |
| addEntry: function(field, index, content='') { | ||
| this.recipe[field].splice(index, 0, content) | ||
| }, | ||
| beforeWindowUnload(e) { | ||
| if (this.confirmStayInEditedForm()) { | ||
| // Cancel the window unload event | ||
| e.preventDefault() | ||
| e.returnValue = '' | ||
| } | ||
| }, | ||
| confirmLeavingPage() { | ||
| return window.confirm('You have unsaved changes! Do you still want to leave?') | ||
| }, | ||
| confirmStayInEditedForm() { | ||
| return !this.savingRecipe && this.formDirty && !this.confirmLeavingPage() | ||
| }, | ||
| deleteEntry: function(field, index) { | ||
| this.recipe[field].splice(index, 1) | ||
| }, | ||
|
|
@@ -251,6 +276,7 @@ export default { | |
| } | ||
| }, | ||
| setup: function() { | ||
| let $this = this | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. May I ask, mainly out of curiosity, why we need a
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good spot :o I introduced it for the $nextTick callback. But actually it’s not necessary since $nextTick is invoked in the |
||
| this.fetchCategories() | ||
| this.fetchKeywords() | ||
| if (this.$route.params.id) { | ||
|
|
@@ -294,7 +320,11 @@ export default { | |
| this.initEmptyRecipe() | ||
| this.$store.dispatch('setPage', { page: 'create' }) | ||
| } | ||
| this.recipeInit = this.recipe | ||
| this.recipeInit = JSON.parse(JSON.stringify(this.recipe)) | ||
| this.$nextTick(function() { | ||
| $this.formDirty = false | ||
| }) | ||
|
|
||
| }, | ||
| initEmptyRecipe: function() { | ||
| this.prepTime = { time: [0, 0], paddedTime: '' } | ||
|
|
@@ -318,6 +348,7 @@ export default { | |
| recipeInstructions: [], | ||
| nutrition: {} | ||
| } | ||
| this.formDirty = false | ||
| } | ||
| }, | ||
| mounted () { | ||
|
|
@@ -331,12 +362,17 @@ export default { | |
| this.$root.$off('saveRecipe') | ||
| this.$root.$on('saveRecipe', () => { | ||
| this.save() | ||
| this.savingRecipe = true | ||
|
christianlupus marked this conversation as resolved.
Outdated
|
||
| }) | ||
| // Register data load method hook for access from the controls components | ||
| this.$root.$off('reloadRecipeEdit') | ||
| this.$root.$on('reloadRecipeEdit', () => { | ||
| this.loadRecipeData() | ||
| }) | ||
| this.savingRecipe = false | ||
| }, | ||
| beforeDestroy() { | ||
| window.removeEventListener('beforeunload', this.beforeWindowUnload) | ||
| }, | ||
| // We can check if the user has browsed from the same recipe's view to this | ||
| // edit and save some time by not reloading the recipe data, leading to a | ||
|
|
@@ -363,13 +399,19 @@ export default { | |
| * This can also be used to confirm that the user wants to leave the page | ||
| * if there are unsaved changes. | ||
| */ | ||
| beforeRouteLeave (to, from, next) { | ||
| beforeRouteLeave (to, from, next) { | ||
| // beforeRouteLeave is called when the static route changes. | ||
| // We have to check if the target component stays the same and reload. | ||
| // However, we should not reload if the component changes; otherwise | ||
| // reloaded data may overwrite the data loaded at the target component | ||
| // which will at the very least result in incorrect breadcrumb path! | ||
| next() | ||
| // Cancel the navigation, if the form has unsaved edits and the user did not | ||
| // confirm leave. This prevents accidentally losing changes | ||
| if (this.confirmStayInEditedForm()){ | ||
| next(false) | ||
| } else { | ||
| // We have to check if the target component stays the same and reload. | ||
| // However, we should not reload if the component changes; otherwise | ||
| // reloaded data may overwrite the data loaded at the target component | ||
| // which will at the very least result in incorrect breadcrumb path! | ||
| next() | ||
| } | ||
| // Check if we should reload the component content | ||
| if (this.$window.shouldReloadContent(from.fullPath, to.fullPath)) { | ||
| this.setup() | ||
|
|
@@ -383,7 +425,9 @@ export default { | |
| this.setup() | ||
| } | ||
| }, | ||
|
|
||
| created() { | ||
| window.addEventListener('beforeunload', this.beforeWindowUnload) | ||
| }, | ||
| } | ||
| </script> | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will continue to new URL when a saving action is just running, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea was: If the user clicked the save button (saving is running), the browser continues to the new URL without checking if the form is dirty (
this.formDirty) and (if it is dirty) asking for confirmation (!this.confirmLeavingPage())There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I see that. This is more related to the overall comment below about the abort of a saving action.