diff options
| author | Vojta Jina | 2012-01-13 16:38:08 -0800 | 
|---|---|---|
| committer | Vojta Jina | 2012-01-14 11:23:12 -0800 | 
| commit | c49b8a2db5d916a9213547125af996d6c853230c (patch) | |
| tree | d8e4d639306790d2466ba01b15410342db4c2d7c | |
| parent | 5cdfe45aa3e50fabad44009c1b8511253c6e4915 (diff) | |
| download | angular.js-c49b8a2db5d916a9213547125af996d6c853230c.tar.bz2 | |
fix($location): do not $digest if browser's url change fired within $apply/$digest
Chrome (probably other browsers as well) fires 'hashchange' event synchronously, so if you change raw location from within $apply/$digest, we don't want to $apply twice. (It would throw an exception)
| -rw-r--r-- | src/service/location.js | 6 | ||||
| -rw-r--r-- | test/service/locationSpec.js | 37 | 
2 files changed, 41 insertions, 2 deletions
| diff --git a/src/service/location.js b/src/service/location.js index d0ae9de7..3e8ba0c3 100644 --- a/src/service/location.js +++ b/src/service/location.js @@ -530,8 +530,10 @@ function $LocationProvider(){      // update $location when $browser url changes      $browser.onUrlChange(function(newUrl) {        if (currentUrl.absUrl() != newUrl) { -        currentUrl.$$parse(newUrl); -        $rootScope.$apply(); +        $rootScope.$evalAsync(function() { +          currentUrl.$$parse(newUrl); +        }); +        if (!$rootScope.$$phase) $rootScope.$digest();        }      }); diff --git a/test/service/locationSpec.js b/test/service/locationSpec.js index c7cc9c23..97f2ab63 100644 --- a/test/service/locationSpec.js +++ b/test/service/locationSpec.js @@ -364,6 +364,43 @@ describe('$location', function() {      })); +    // location.href = '...' fires hashchange event synchronously, so it might happen inside $apply +    it('should not $apply when browser url changed inside $apply', inject( +        function($rootScope, $browser, $location) { +      var OLD_URL = $browser.url(), +          NEW_URL = 'http://updated.com/url'; + + +      $rootScope.$apply(function() { +        $browser.url(NEW_URL); +        $browser.poll(); // simulate firing event from browser +        expect($location.absUrl()).toBe(OLD_URL); // should be async +      }); + +      expect($location.absUrl()).toBe(NEW_URL); +    })); + +    // location.href = '...' fires hashchange event synchronously, so it might happen inside $digest +    it('should not $apply when browser url changed inside $digest', inject( +        function($rootScope, $browser, $location) { +      var OLD_URL = $browser.url(), +          NEW_URL = 'http://updated.com/url', +          notRunYet = true; + +      $rootScope.$watch(function() { +        if (notRunYet) { +          notRunYet = false; +          $browser.url(NEW_URL); +          $browser.poll(); // simulate firing event from browser +          expect($location.absUrl()).toBe(OLD_URL); // should be async +        } +      }); + +      $rootScope.$digest(); +      expect($location.absUrl()).toBe(NEW_URL); +    })); + +      it('should update browser when $location changes', inject(function($rootScope, $browser, $location) {        var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough();        $location.path('/new/path'); | 
