From 882953d971ba443117d7bb0520d5403c7a69ab2a Mon Sep 17 00:00:00 2001 From: Jeff Cross Date: Fri, 2 Aug 2013 09:21:33 -0700 Subject: [PATCH 1/2] fix(docs-bootstrap): Removed injector from bootstrapped docs samples This is necessary to make e2e tests pass for implementing #3411. At present, the docs are violating the rule being enforced by double-bootstrap prevention. --- .../angular-bootstrap/bootstrap-prettify.js | 1 + src/jqLite.js | 2 +- test/jqLiteSpec.js | 14 ++++++++++++++ test/testabilityPatch.js | 2 +- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/components/angular-bootstrap/bootstrap-prettify.js b/docs/components/angular-bootstrap/bootstrap-prettify.js index b42c7c3a7b2c..9d8a7d23482e 100644 --- a/docs/components/angular-bootstrap/bootstrap-prettify.js +++ b/docs/components/angular-bootstrap/bootstrap-prettify.js @@ -241,6 +241,7 @@ directive.ngEmbedApp = ['$templateCache', '$browser', '$rootScope', '$location', embedRootScope.$destroy(); }); + element.data('$injector', null); angular.bootstrap(element, modules); } }; diff --git a/src/jqLite.js b/src/jqLite.js index 6ac9998792a0..4a52cba018f8 100644 --- a/src/jqLite.js +++ b/src/jqLite.js @@ -330,7 +330,7 @@ function JQLiteInheritedData(element, name, value) { } while (element.length) { - if (value = element.data(name)) return value; + if ((value = element.data(name)) !== undefined) return value; element = element.parent(); } } diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js index abfad064632a..913e61924726 100644 --- a/test/jqLiteSpec.js +++ b/test/jqLiteSpec.js @@ -126,6 +126,20 @@ describe('jqLite', function() { dealoc(doc); } ); + + it('should return null values', function () { + var ul = jqLite(''), + li = ul.find('li'), + b = li.find('b'); + + ul.data('foo', 'bar'); + li.data('foo', null); + expect(b.inheritedData('foo')).toBe(null); + expect(li.inheritedData('foo')).toBe(null); + expect(ul.inheritedData('foo')).toBe('bar'); + + dealoc(ul); + }); }); diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js index 7b4fe0ec1abf..514a5fdbbdbd 100644 --- a/test/testabilityPatch.js +++ b/test/testabilityPatch.js @@ -56,7 +56,7 @@ afterEach(function() { forEachSorted(cache, function(expando, key){ angular.forEach(expando.data, function(value, key){ count ++; - if (value.$element) { + if (value && value.$element) { dump('LEAK', key, value.$id, sortedHtml(value.$element)); } else { dump('LEAK', key, angular.toJson(value)); From d71f9c86cb49b6dae9934301edb32ce9788fbfdd Mon Sep 17 00:00:00 2001 From: Jeff Cross Date: Wed, 24 Jul 2013 10:17:24 -0700 Subject: [PATCH 2/2] fix(re-bootstrap): Throw an error when bootstrapping a bootstrapped element. Nothing would prevent a user from accidentally calling angular.bootstrap on an element that had already been bootstrapped. If this was done, odd behavior could manifest in an application, causing different scopes to update the same DOM, and causing debugger confusion. This fix adds a check inside of angular.bootstrap to check if the passed-in element already contains a class of ng-scope, and if so, will throw an error. --- docs/content/error/ng/btstrpd.ngdoc | 29 +++++++++++++++++++++++++++++ src/Angular.js | 6 ++++++ test/AngularSpec.js | 26 ++++++++++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 docs/content/error/ng/btstrpd.ngdoc diff --git a/docs/content/error/ng/btstrpd.ngdoc b/docs/content/error/ng/btstrpd.ngdoc new file mode 100644 index 000000000000..401e276720fa --- /dev/null +++ b/docs/content/error/ng/btstrpd.ngdoc @@ -0,0 +1,29 @@ +@ngdoc error +@name ng:btstrpd +@fullName App Already Bootstrapped with this Element +@description + +Occurs when calling angular.bootstrap on an element that has already been bootstrapped. + +This usually happens when you accidentally use both `ng-app` and `angular.bootstrap` to bootstrap an application. + +``` + +... + + + + +``` + +Note that for bootrapping purposes, the `` element is the same as `document`, so the following will also throw an error. +``` + +... + + +``` diff --git a/src/Angular.js b/src/Angular.js index 1a90f8bc0f98..90c7234a33bf 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -1049,6 +1049,12 @@ function angularInit(element, bootstrap) { function bootstrap(element, modules) { var doBootstrap = function() { element = jqLite(element); + + if (element.injector()) { + var tag = (element[0] === document) ? 'document' : startingTag(element); + throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag); + } + modules = modules || []; modules.unshift(['$provide', function($provide) { $provide.value('$rootElement', element); diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 56fc985ca6b6..f049c2fd0c05 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -656,6 +656,32 @@ describe('angular', function() { /\[\$injector:modulerr] Failed to instantiate module doesntexist due to:\n.*\[\$injector:nomod] Module 'doesntexist' is not available! You either misspelled the module name or forgot to load it\./ ); }); + + + it('should complain if an element has already been bootstrapped', function () { + var element = jqLite('
bootstrap me!
'); + angular.bootstrap(element); + + expect(function () { + angular.bootstrap(element); + }).toThrowMatching( + /\[ng:btstrpd\] App Already Bootstrapped with this Element '
'/i + ); + + dealoc(element); + }); + + + it('should complain if manually bootstrapping a document whose element has already been bootstrapped', function () { + angular.bootstrap(document.getElementsByTagName('html')[0]); + expect(function () { + angular.bootstrap(document); + }).toThrowMatching( + /\[ng:btstrpd\] App Already Bootstrapped with this Element 'document'/i + ); + + dealoc(document); + }) });