diff options
| -rw-r--r-- | src/loader.js | 13 | ||||
| -rw-r--r-- | src/service/controller.js | 51 | ||||
| -rw-r--r-- | test/directive/ngViewSpec.js | 19 | ||||
| -rw-r--r-- | test/loaderSpec.js | 2 | ||||
| -rw-r--r-- | test/service/controllerSpec.js | 41 | 
5 files changed, 114 insertions, 12 deletions
| diff --git a/src/loader.js b/src/loader.js index fdfdaebd..b25fc40e 100644 --- a/src/loader.js +++ b/src/loader.js @@ -167,7 +167,7 @@ function setupModuleLoader(window) {             * @ngdoc method             * @name angular.Module#filter             * @methodOf angular.Module -           * @param {string} name filter name +           * @param {string} name Filter name.             * @param {Function} filterFactory Factory function for creating new instance of filter.             * @description             * See {@link angular.module.ng.$filterProvider#register $filterProvider.register()}. @@ -176,6 +176,17 @@ function setupModuleLoader(window) {            /**             * @ngdoc method +           * @name angular.Module#controller +           * @methodOf angular.Module +           * @param {string} name Controller name. +           * @param {Function} constructor Controller constructor function. +           * @description +           * See {@link angular.module.ng.$controllerProvider#register $controllerProvider.register()}. +           */ +          controller: invokeLater('$controllerProvider', 'register'), + +          /** +           * @ngdoc method             * @name angular.Module#directive             * @methodOf angular.Module             * @param {string} name directive name diff --git a/src/service/controller.js b/src/service/controller.js index 229ce14a..fa90f8cd 100644 --- a/src/service/controller.js +++ b/src/service/controller.js @@ -1,6 +1,32 @@  'use strict'; +/** + * @ngdoc object + * @name angular.module.ng.$controllerProvider + * @description + * The {@link angular.module.ng.$controller $controller service} is used by Angular to create new + * controllers. + * + * This provider allows controller registration via the + * {@link angular.module.ng.$controllerProvider#register register} method. + */  function $ControllerProvider() { +  var controllers = {}; + + +  /** +   * @ngdoc function +   * @name angular.module.ng.$controllerProvider#register +   * @methodOf angular.module.ng.$controllerProvider +   * @param {string} name Controller name +   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI +   *    annotations in the array notation). +   */ +  this.register = function(name, constructor) { +    controllers[name] = constructor; +  }; + +    this.$get = ['$injector', '$window', function($injector, $window) {      /** @@ -8,8 +34,14 @@ function $ControllerProvider() {       * @name angular.module.ng.$controller       * @requires $injector       * -     * @param {Function|string} Class Constructor function of a controller to instantiate, or -     *        expression to read from current scope or window. +     * @param {Function|string} constructor If called with a function then it's considered to be the +     *    controller constructor function. Otherwise it's considered to be a string which is used +     *    to retrieve the controller constructor using the following steps: +     * +     *    * check if a controller with given name is registered via `$controllerProvider` +     *    * check if evaluating the string on the current scope returns a constructor +     *    * check `window[constructor]` on the global `window` object +     *       * @param {Object} locals Injection locals for Controller.       * @return {Object} Instance of given controller.       * @@ -20,14 +52,17 @@ function $ControllerProvider() {       * a service, so that one can override this service with {@link https://gist.github.com/1649788       * BC version}.       */ -    return function(Class, locals) { -      if(isString(Class)) { -        var expression = Class; -        Class = getter(locals.$scope, expression, true) || getter($window, expression, true); -        assertArgFn(Class, expression); +    return function(constructor, locals) { +      if(isString(constructor)) { +        var name = constructor; +        constructor = controllers.hasOwnProperty(name) +            ? controllers[name] +            : getter(locals.$scope, name, true) || getter($window, name, true); + +        assertArgFn(constructor, name, true);        } -      return $injector.instantiate(Class, locals); +      return $injector.instantiate(constructor, locals);      };    }];  } diff --git a/test/directive/ngViewSpec.js b/test/directive/ngViewSpec.js index 52aefa3a..636e15a8 100644 --- a/test/directive/ngViewSpec.js +++ b/test/directive/ngViewSpec.js @@ -54,6 +54,25 @@ describe('ng-view', function() {    }); +  it('should support string controller declaration', function() { +    var MyCtrl = jasmine.createSpy('MyCtrl'); + +    module(function($controllerProvider, $routeProvider) { +      $controllerProvider.register('MyCtrl', ['$scope', MyCtrl]); +      $routeProvider.when('/foo', {controller: 'MyCtrl', template: '/tpl.html'}); +    }); + +    inject(function($route, $location, $rootScope, $templateCache) { +      $templateCache.put('/tpl.html', [200, '<div></div>', {}]); +      $location.path('/foo'); +      $rootScope.$digest(); + +      expect($route.current.controller).toBe('MyCtrl'); +      expect(MyCtrl).toHaveBeenCalledWith(element.contents().scope()); +    }); +  }); + +    it('should load content via xhr when route changes', function() {      module(function($routeProvider) {        $routeProvider.when('/foo', {template: 'myUrl1'}); diff --git a/test/loaderSpec.js b/test/loaderSpec.js index dff3787d..b2341a71 100644 --- a/test/loaderSpec.js +++ b/test/loaderSpec.js @@ -38,6 +38,7 @@ describe('module loader', function() {        value('k', 'v').        filter('f', 'ff').        directive('d', 'dd'). +      controller('ctrl', 'ccc').        config('init2').        constant('abc', 123).        run('runBlock')).toBe(myModule); @@ -52,6 +53,7 @@ describe('module loader', function() {        ['$provide', 'value', ['k', 'v'] ],        ['$filterProvider', 'register', ['f', 'ff'] ],        ['$compileProvider', 'directive', ['d', 'dd'] ], +      ['$controllerProvider', 'register', ['ctrl', 'ccc']],        ['$injector', 'invoke', ['init2'] ]      ]);      expect(myModule._runBlocks).toEqual(['runBlock']); diff --git a/test/service/controllerSpec.js b/test/service/controllerSpec.js index 2c0f8c62..91389013 100644 --- a/test/service/controllerSpec.js +++ b/test/service/controllerSpec.js @@ -1,12 +1,47 @@  'use strict';  describe('$controller', function() { -  var $controller; +  var $controllerProvider, $controller; -  beforeEach(inject(function($injector) { -    $controller = $injector.get('$controller'); +  beforeEach(module(function(_$controllerProvider_) { +    $controllerProvider = _$controllerProvider_;    })); + +  beforeEach(inject(function(_$controller_) { +    $controller = _$controller_; +  })); + + +  describe('provider', function() { + +    it('should allow registration of controllers', function() { +      var FooCtrl = function($scope) { $scope.foo = 'bar' }, +          scope = {}, +          ctrl; + +      $controllerProvider.register('FooCtrl', FooCtrl); +      ctrl = $controller('FooCtrl', {$scope: scope}); + +      expect(scope.foo).toBe('bar'); +      expect(ctrl instanceof FooCtrl).toBe(true); +    }); + + +    it('should allow registration of controllers annotated with arrays', function() { +      var FooCtrl = function($scope) { $scope.foo = 'bar' }, +          scope = {}, +          ctrl; + +      $controllerProvider.register('FooCtrl', ['$scope', FooCtrl]); +      ctrl = $controller('FooCtrl', {$scope: scope}); + +      expect(scope.foo).toBe('bar'); +      expect(ctrl instanceof FooCtrl).toBe(true); +    }); +  }); + +    it('should return instance of given controller class', function() {      var MyClass = function() {},          ctrl = $controller(MyClass); | 
