diff --git a/src/ng/compile.js b/src/ng/compile.js index 3de0d53f0388..df5185020f5e 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1967,13 +1967,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { for (i in elementControllers) { controller = elementControllers[i]; var controllerResult = controller(); - if (controllerResult !== controller.instance && - controller === controllerForBindings) { - // Remove and re-install bindToController bindings - thisLinkFn.$$destroyBindings(); - thisLinkFn.$$destroyBindings = - initializeDirectiveBindings(scope, attrs, controllerResult, - bindings, scopeDirective); + if (controllerResult !== controller.instance) { + controller.instance = controllerResult; + $element.data('$' + directive.name + 'Controller', controllerResult); + if (controller === controllerForBindings) { + // Remove and re-install bindToController bindings + thisLinkFn.$$destroyBindings(); + thisLinkFn.$$destroyBindings = + initializeDirectiveBindings(scope, attrs, controllerResult, bindings, scopeDirective); + } } } } diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index d1f97246774c..b30ab8631d9a 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -4197,6 +4197,130 @@ describe('$compile', function() { }); + it('should respect explicit return value from controller', function() { + module(function() { + directive('logControllerProp', function(log) { + return { + controller: function($scope) { + this.foo = 'baz'; // value should not be used. + return {foo: 'bar'}; + }, + link: function(scope, element, attrs, controller) { + log(controller.foo); + } + }; + }); + }); + inject(function(log, $compile, $rootScope) { + element = $compile('')($rootScope); + expect(log).toEqual('bar'); + expect(element.data('$logControllerPropController').foo).toEqual('bar'); + }); + }); + + + it('should get explicit return value of required parent controller', function() { + module(function() { + directive('nested', function(log) { + return { + require: '^^?nested', + controller: function() { + return {foo: 'bar'}; + }, + link: function(scope, element, attrs, controller) { + log(!!controller && controller.foo); + } + }; + }); + }); + inject(function(log, $compile, $rootScope) { + element = $compile('
')($rootScope); + + expect(log).toEqual('bar; false'); + }); + }); + + + it('should respect explicit controller return value when using controllerAs', function() { + module(function() { + directive('main', function() { + return { + templateUrl: 'main.html', + scope: {}, + controller: function() { + this.name = 'lucas'; + return {name: 'george'}; + }, + controllerAs: 'mainCtrl' + }; + }); + }); + inject(function($templateCache, $compile, $rootScope) { + $templateCache.put('main.html', 'template:{{mainCtrl.name}}'); + element = $compile('
')($rootScope); + $rootScope.$apply(); + expect(element.text()).toBe('template:george'); + }); + }); + + + it('transcluded children should receive explicit return value of parent controller', function() { + var expectedController; + module(function() { + directive('nester', valueFn({ + transclude: 'content', + controller: function($transclude) { + this.foo = 'baz'; + expectedController = {transclude:$transclude, foo: 'bar'}; + return expectedController; + }, + link: function(scope, el, attr, ctrl) { + ctrl.transclude(cloneAttach); + function cloneAttach(clone) { + el.append(clone); + } + } + })); + directive('nested', function(log) { + return { + require: '^^nester', + link: function(scope, element, attrs, controller) { + expect(controller).toBe(expectedController); + log('done'); + } + }; + }); + }); + inject(function(log, $compile) { + element = $compile('
')($rootScope); + $rootScope.$apply(); + expect(log).toEqual('done'); + }); + }); + + + it('explicit controller return values are ignored if they are primitives', function() { + module(function() { + directive('logControllerProp', function(log) { + return { + controller: function($scope) { + this.foo = 'baz'; // value *will* be used. + return 'bar'; + }, + link: function(scope, element, attrs, controller) { + log(controller.foo); + } + }; + }); + }); + inject(function(log, $compile, $rootScope) { + element = $compile('')($rootScope); + expect(log).toEqual('baz'); + expect(element.data('$logControllerPropController').foo).toEqual('baz'); + }); + }); + + it('should get required parent controller', function() { module(function() { directive('nested', function(log) {