change ng:controller to create new scope hence allow nesting

This commit is contained in:
Misko Hevery 2010-10-06 17:01:41 -07:00
parent c30807d141
commit 772e32c220
3 changed files with 56 additions and 23 deletions

View file

@ -9,40 +9,42 @@ function Template(priority) {
this.children = [];
this.inits = [];
this.priority = priority;
this.newScope = false;
}
Template.prototype = {
init: function(element, scope) {
var inits = {};
this.collectInits(element, inits);
this.collectInits(element, inits, scope);
foreachSorted(inits, function(queue){
foreach(queue, function(fn){
fn(scope);
});
foreach(queue, function(fn) {fn();});
});
},
collectInits: function(element, inits) {
var queue = inits[this.priority];
collectInits: function(element, inits, scope) {
var queue = inits[this.priority], childScope = scope;
if (!queue) {
inits[this.priority] = queue = [];
}
element = jqLite(element);
if (this.newScope) {
childScope = createScope(scope);
scope.$onEval(childScope.$eval);
}
foreach(this.inits, function(fn) {
queue.push(function(scope) {
scope.$tryEval(function(){
return fn.call(scope, element);
queue.push(function() {
childScope.$tryEval(function(){
return fn.call(childScope, element);
}, element);
});
});
var i,
childNodes = element[0].childNodes,
children = this.children,
paths = this.paths,
length = paths.length;
for (i = 0; i < length; i++) {
children[i].collectInits(childNodes[paths[i]], inits);
children[i].collectInits(childNodes[paths[i]], inits, childScope);
}
},
@ -121,7 +123,8 @@ Compiler.prototype = {
element:function(type) {return jqLite(document.createElement(type));},
text:function(text) {return jqLite(document.createTextNode(text));},
descend: function(value){ if(isDefined(value)) descend = value; return descend;},
directives: function(value){ if(isDefined(value)) directives = value; return directives;}
directives: function(value){ if(isDefined(value)) directives = value; return directives;},
scope: function(value){ if(isDefined(value)) template.newScope = template.newScope || value ; return template.newScope;}
};
try {
priority = element.attr('ng:eval-order') || priority || 0;

View file

@ -5,6 +5,7 @@ angularDirective("ng:init", function(expression){
});
angularDirective("ng:controller", function(expression){
this.scope(true);
return function(element){
var controller = getter(window, expression, true) || getter(this, expression, true);
if (!controller)
@ -12,7 +13,6 @@ angularDirective("ng:controller", function(expression){
if (!isFunction(controller))
throw "Reference '"+expression+"' is not a class.";
this.$become(controller);
(this.init || noop)();
};
});

View file

@ -254,23 +254,53 @@ describe("directives", function(){
});
describe('ng:controller', function(){
it('should bind', function(){
window.Greeter = function(){
var temp;
beforeEach(function(){
temp = window.temp = {};
temp.Greeter = function(){
this.$root.greeter = this;
this.greeting = 'hello';
this.suffix = '!';
};
window.Greeter.prototype = {
init: function(){
this.suffix = '!';
},
temp.Greeter.prototype = {
greet: function(name) {
return this.greeting + ' ' + name + this.suffix;
}
};
var scope = compile('<div ng:controller="Greeter"></div>');
expect(scope.greeting).toEqual('hello');
expect(scope.greet('misko')).toEqual('hello misko!');
window.Greeter = undefined;
});
afterEach(function(){
window.temp = undefined;
});
it('should bind', function(){
var scope = compile('<div ng:controller="temp.Greeter"></div>');
expect(scope.greeter.greeting).toEqual('hello');
expect(scope.greeter.greet('misko')).toEqual('hello misko!');
});
it('should support nested controllers', function(){
temp.ChildGreeter = function() {
this.greeting = 'hey';
this.$root.childGreeter = this;
};
temp.ChildGreeter.prototype = {
greet: function() {
return this.greeting + ' dude' + this.suffix;
}
};
var scope = compile('<div ng:controller="temp.Greeter"><div ng:controller="temp.ChildGreeter">{{greet("misko")}}</div></div>');
expect(scope.greeting).not.toBeDefined();
expect(scope.greeter.greeting).toEqual('hello');
expect(scope.greeter.greet('misko')).toEqual('hello misko!');
expect(scope.greeter.greeting).toEqual('hello');
expect(scope.childGreeter.greeting).toEqual('hey');
expect(scope.childGreeter.$parent.greeting).toEqual('hello');
expect(scope.$element.text()).toEqual('hey dude!');
});
});
it('should eval things according to ng:eval-order', function(){