{"id":1785,"date":"2022-08-30T15:19:25","date_gmt":"2022-08-30T15:19:25","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2013\/12\/02\/prevent-redirect-behaviour-in-angularjs-app-collection-of-common-programming-errors\/"},"modified":"2022-08-30T15:19:25","modified_gmt":"2022-08-30T15:19:25","slug":"prevent-redirect-behaviour-in-angularjs-app-collection-of-common-programming-errors","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2022\/08\/30\/prevent-redirect-behaviour-in-angularjs-app-collection-of-common-programming-errors\/","title":{"rendered":"prevent redirect behaviour in angularjs app-Collection of common programming errors"},"content":{"rendered":"<p>There are two DOM events at the root of this whole problem you&#8217;re trying to solve: onhashchange and onbeforeunload. onhashchange can be checked and prevented, however, the Back button on your browser will not trigger onhashchange. What&#8217;s worse, onbeforeunload will not trigger if the page doesn&#8217;t reload, which means if you hit Back to go to a previous hash on the page, it will not fire. Because of this, if you press Back to to go a previous route it will still leave your form.<\/p>\n<p>There is also currently an oustanding issue on Angular&#8217;s todo list about how they&#8217;re going to allow for the cancellation of a route. I&#8217;d presume the back button to a hash issue is what&#8217;s hold them up at this point.<\/p>\n<p>So in the end you may want to re-engineer your solution to do something a little more drastic if you want to prevent all navigation away from your form once it&#8217;s been edited. Something like storing all of the data the form is editing in $rootScope, along with a flag to show that it&#8217;s dirty but incomplete, then add an event handler to routeChangeStart that checks those values and sends you back to the form.<\/p>\n<p>Here&#8217;s how that would work (and a plunker if you&#8217;re interested):<\/p>\n<pre><code>app.config(function($routeProvider) {\n  \/\/set up the routes. (Important because we're going to navigate\n  \/\/ BACK to them.)\n  $routeProvider.when('\/Form', {\n    controller: 'FormCtrl',\n    templateUrl: 'form.html'\n  }).otherwise({\n    controller: 'HomeCtrl',\n    template: '<\/code><\/pre>\n<h3><code>Home<\/code><\/h3>\n<pre>' \n  });\n});\n\napp.run(function($rootScope, $location){ \n  \/\/set up your rootScope formData object.\n  $rootScope.formData = {};\n\n  \/\/add a routing event to check the route\n  \/\/ and whether or not the data has been editted and then \n  \/\/ send it back to the proper form.\n  $rootScope.$on('$routeChangeStart', function() {\n    if($location.path() != '\/Form' &amp;&amp; $rootScope.formData.dirty &amp;&amp; \n      !$rootScope.formData.complete &amp;&amp; !confirm('Do you want to leave this form?')) {\n      $location.path('\/Form');\n    }\n  });\n\n  \/\/handle outright navigating away from the page.\n  $(window).on('beforeunload', function() {\n     if($rootScope.formData.dirty &amp;&amp; \n      !$rootScope.formData.complete) {\n         return 'Are you sure you want to navigate away from this form?';\n     }\n  });\n});\n\napp.controller('FormCtrl', function($scope) {\n  $scope.$watch(function (){\n    return $scope.myForm.$dirty;\n  }, function(dirty) {\n    $scope.formData.dirty = $scope.formData.dirty | dirty;\n  })\n});\n<\/pre>\n<p><code>other thoughts<\/code><\/p>\n<p><code>Initially I had developed a directive to help with this, but I realized that it wouldn't work because of the issues I mentioned above. Regardless, for posterity's sake, here it is:<\/code><\/p>\n<pre><code><code>app.directive('form', function ($window){\n  return {\n    restrict: 'E',\n    link: function(scope, elem, attrs) {\n\n      \/\/check for a prevent-if-dirty attribute on your form tag\n      if(attrs.preventIfDirty !== undefined) {\n\n        \/\/ first off, stop routing hash changes from \n        \/\/ changing the page.\n        scope.$on('$locationChangeStart', function(event) {\n          if(scope.testForm.$dirty) {\n            event.preventDefault();\n          }\n        });\n\n        \/\/ a little setup for our next piece\n        var formName = attrs.name;\n        function showWarning() {\n          return 'You have changed the form';\n        }\n\n        \/\/ Now stop browser navigation from moving away\n        \/\/ from your dirty form.\n        scope.$watch(function (){\n          return scope[formName].$dirty;\n        }, function(dirty) {\n          if(dirty) {\n             $(window).on('beforeunload', showWarning);\n          } else {\n             $(window).off('beforeunload', showWarning);\n          }\n        });\n      }\n    }\n  };\n});\n<\/code><\/code><\/pre>\n<p>Here&#8217;s a plunker demonstrating it.<\/p>\n<p id=\"rop\"><small>Originally posted 2013-12-02 01:31:11. <\/small><\/p>","protected":false},"excerpt":{"rendered":"<p>There are two DOM events at the root of this whole problem you&#8217;re trying to solve: onhashchange and onbeforeunload. onhashchange can be checked and prevented, however, the Back button on your browser will not trigger onhashchange. What&#8217;s worse, onbeforeunload will not trigger if the page doesn&#8217;t reload, which means if you hit Back to go [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1785","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/1785","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=1785"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/1785\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=1785"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=1785"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=1785"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}