Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

Commit

Permalink
feat($controller): support controller registration via $controllerPro…
Browse files Browse the repository at this point in the history
…vider

It's now possible to register controllers as:

.register('MyCtrl', function($scope) { ... });
// or
.register('MyCtrl', ['$scope', function($scope) { ... });

Additionally a module loader shortcut api was added as well:

myModule.controller('MyCtr', function($scope) { ... });
  • Loading branch information
IgorMinar committed Mar 26, 2012
1 parent 4b8d926 commit d54dfec
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 12 deletions.
13 changes: 12 additions & 1 deletion src/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,24 @@ 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()}.
*/
filter: invokeLater('$filterProvider', 'register'),

/**
* @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
Expand Down
51 changes: 43 additions & 8 deletions src/service/controller.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
'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) {

/**
* @ngdoc function
* @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.
*
Expand All @@ -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);
};
}];
}
19 changes: 19 additions & 0 deletions test/directive/ngViewSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'});
Expand Down
2 changes: 2 additions & 0 deletions test/loaderSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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']);
Expand Down
41 changes: 38 additions & 3 deletions test/service/controllerSpec.js
Original file line number Diff line number Diff line change
@@ -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);
Expand Down

0 comments on commit d54dfec

Please sign in to comment.