From ef4cd8dce39d2dddfa06b0b6b16ca669fee66d53 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 17 Jun 2014 11:57:07 -0400 Subject: [PATCH] fix(loader): allow 'ng' module to be extended with filters/directives/etc Due to a regression in c0b4e2d, it is no longer possible to add new controllers, directives, filters, or animations to the `ng` module. This is becuase `config` blocks are always evaluated after regular invoke blocks, and the registration of these types depend on angular's config blocks to have been run. This solution simply ensures that `ng`'s config blocks are run before its invoke blocks are run. Closes #7709 --- src/auto/injector.js | 4 +++- test/loaderSpec.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/auto/injector.js b/src/auto/injector.js index 08fa4f756b9b..3c343fd7731c 100644 --- a/src/auto/injector.js +++ b/src/auto/injector.js @@ -712,8 +712,10 @@ function createInjector(modulesToLoad, strictDi) { if (isString(module)) { moduleFn = angularModule(module); runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks); + var isCore = module === 'ng'; + if (isCore) runInvokeQueue(moduleFn._configBlocks); runInvokeQueue(moduleFn._invokeQueue); - runInvokeQueue(moduleFn._configBlocks); + if (!isCore) runInvokeQueue(moduleFn._configBlocks); } else if (isFunction(module)) { runBlocks.push(providerInjector.invoke(module)); } else if (isArray(module)) { diff --git a/test/loaderSpec.js b/test/loaderSpec.js index dbe637269780..d96acf62a302 100644 --- a/test/loaderSpec.js +++ b/test/loaderSpec.js @@ -84,4 +84,46 @@ describe('module loader', function() { it('should expose `$$minErr` on the `angular` object', function() { expect(window.angular.$$minErr).toEqual(jasmine.any(Function)); }); + + describe('extending "ng" module', function() { + var rootElement, angular, run; + beforeEach(function() { + rootElement = jqLite('
'); + jqLite(document.body).append(rootElement); + angular = window.angular; + publishExternalAPI(angular); + run = jasmine.createSpy('run block'); + }); + + afterEach(function() { + expect(run).toHaveBeenCalledOnce(); + rootElement.remove(); + dealoc(rootElement); + }); + + it('should allow filters to be registered', function() { + run.andCallFake(function($filter) { expect($filter('noop')).toBe(noop); }); + angularModule("ng").filter('noop', function() { return noop; }).run(['$filter', run]); + angular.bootstrap(rootElement, []); + }); + + it('should allow directives to be registered', function() { + var linkMe = jasmine.createSpy('linkMe'); + run.andCallFake(function($compile, $rootScope) { + dealoc($compile('
')($rootScope)); + expect(linkMe).toHaveBeenCalledOnce(); + }); + angularModule("ng").directive('linkMe', valueFn(linkMe)).run(['$compile', '$rootScope', run]); + angular.bootstrap(rootElement, []); + }); + + it('should allow controllers to be registered', function() { + function Ctrl($scope) {} + run.andCallFake(function($controller, $rootScope) { + expect($controller('Ctrl', { $scope: $rootScope }) instanceof Ctrl).toBe(true); + }); + angularModule("ng").controller('Ctrl', Ctrl).run(['$controller', '$rootScope', run]); + angular.bootstrap(rootElement, []); + }); + }); });