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

Commit 9900610

Browse files
jamestalmagecaitp
authored andcommitted
fix($compile): update data() when controller returns custom value
When controller functions return an explicit value that value should be what is passed to the linking functions, and to any child/sibling controllers that `require` it. It should also be bound to the data store on the dom element. Closes #11147 Closes #11326
1 parent db866f1 commit 9900610

File tree

2 files changed

+133
-7
lines changed

2 files changed

+133
-7
lines changed

src/ng/compile.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -1978,13 +1978,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
19781978
for (i in elementControllers) {
19791979
controller = elementControllers[i];
19801980
var controllerResult = controller();
1981-
if (controllerResult !== controller.instance &&
1982-
controller === controllerForBindings) {
1983-
// Remove and re-install bindToController bindings
1984-
thisLinkFn.$$destroyBindings();
1985-
thisLinkFn.$$destroyBindings =
1986-
initializeDirectiveBindings(scope, attrs, controllerResult,
1987-
bindings, scopeDirective);
1981+
if (controllerResult !== controller.instance) {
1982+
controller.instance = controllerResult;
1983+
$element.data('$' + directive.name + 'Controller', controllerResult);
1984+
if (controller === controllerForBindings) {
1985+
// Remove and re-install bindToController bindings
1986+
thisLinkFn.$$destroyBindings();
1987+
thisLinkFn.$$destroyBindings =
1988+
initializeDirectiveBindings(scope, attrs, controllerResult, bindings, scopeDirective);
1989+
}
19881990
}
19891991
}
19901992
}

test/ng/compileSpec.js

+124
Original file line numberDiff line numberDiff line change
@@ -4197,6 +4197,130 @@ describe('$compile', function() {
41974197
});
41984198

41994199

4200+
it('should respect explicit return value from controller', function() {
4201+
module(function() {
4202+
directive('logControllerProp', function(log) {
4203+
return {
4204+
controller: function($scope) {
4205+
this.foo = 'baz'; // value should not be used.
4206+
return {foo: 'bar'};
4207+
},
4208+
link: function(scope, element, attrs, controller) {
4209+
log(controller.foo);
4210+
}
4211+
};
4212+
});
4213+
});
4214+
inject(function(log, $compile, $rootScope) {
4215+
element = $compile('<log-controller-prop></log-controller-prop>')($rootScope);
4216+
expect(log).toEqual('bar');
4217+
expect(element.data('$logControllerPropController').foo).toEqual('bar');
4218+
});
4219+
});
4220+
4221+
4222+
it('should get explicit return value of required parent controller', function() {
4223+
module(function() {
4224+
directive('nested', function(log) {
4225+
return {
4226+
require: '^^?nested',
4227+
controller: function() {
4228+
return {foo: 'bar'};
4229+
},
4230+
link: function(scope, element, attrs, controller) {
4231+
log(!!controller && controller.foo);
4232+
}
4233+
};
4234+
});
4235+
});
4236+
inject(function(log, $compile, $rootScope) {
4237+
element = $compile('<div nested><div nested></div></div>')($rootScope);
4238+
4239+
expect(log).toEqual('bar; false');
4240+
});
4241+
});
4242+
4243+
4244+
it('should respect explicit controller return value when using controllerAs', function() {
4245+
module(function() {
4246+
directive('main', function() {
4247+
return {
4248+
templateUrl: 'main.html',
4249+
scope: {},
4250+
controller: function() {
4251+
this.name = 'lucas';
4252+
return {name: 'george'};
4253+
},
4254+
controllerAs: 'mainCtrl'
4255+
};
4256+
});
4257+
});
4258+
inject(function($templateCache, $compile, $rootScope) {
4259+
$templateCache.put('main.html', '<span>template:{{mainCtrl.name}}</span>');
4260+
element = $compile('<main/>')($rootScope);
4261+
$rootScope.$apply();
4262+
expect(element.text()).toBe('template:george');
4263+
});
4264+
});
4265+
4266+
4267+
it('transcluded children should receive explicit return value of parent controller', function() {
4268+
var expectedController;
4269+
module(function() {
4270+
directive('nester', valueFn({
4271+
transclude: 'content',
4272+
controller: function($transclude) {
4273+
this.foo = 'baz';
4274+
expectedController = {transclude:$transclude, foo: 'bar'};
4275+
return expectedController;
4276+
},
4277+
link: function(scope, el, attr, ctrl) {
4278+
ctrl.transclude(cloneAttach);
4279+
function cloneAttach(clone) {
4280+
el.append(clone);
4281+
}
4282+
}
4283+
}));
4284+
directive('nested', function(log) {
4285+
return {
4286+
require: '^^nester',
4287+
link: function(scope, element, attrs, controller) {
4288+
expect(controller).toBe(expectedController);
4289+
log('done');
4290+
}
4291+
};
4292+
});
4293+
});
4294+
inject(function(log, $compile) {
4295+
element = $compile('<div nester><div nested></div></div>')($rootScope);
4296+
$rootScope.$apply();
4297+
expect(log).toEqual('done');
4298+
});
4299+
});
4300+
4301+
4302+
it('explicit controller return values are ignored if they are primitives', function() {
4303+
module(function() {
4304+
directive('logControllerProp', function(log) {
4305+
return {
4306+
controller: function($scope) {
4307+
this.foo = 'baz'; // value *will* be used.
4308+
return 'bar';
4309+
},
4310+
link: function(scope, element, attrs, controller) {
4311+
log(controller.foo);
4312+
}
4313+
};
4314+
});
4315+
});
4316+
inject(function(log, $compile, $rootScope) {
4317+
element = $compile('<log-controller-prop></log-controller-prop>')($rootScope);
4318+
expect(log).toEqual('baz');
4319+
expect(element.data('$logControllerPropController').foo).toEqual('baz');
4320+
});
4321+
});
4322+
4323+
42004324
it('should get required parent controller', function() {
42014325
module(function() {
42024326
directive('nested', function(log) {

0 commit comments

Comments
 (0)