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

Commit 7c49b25

Browse files
author
Misko Hevery
committed
$invalid widget clear on switch change
1 parent 713307b commit 7c49b25

File tree

5 files changed

+80
-8
lines changed

5 files changed

+80
-8
lines changed

angular-debug.js

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ var consoleNode,
3333
PRIORITY_FIRST = -99999,
3434
PRIORITY_WATCH = -1000,
3535
PRIORITY_LAST = 99999,
36+
PRIORITY = {'FIRST': PRIORITY_FIRST, 'LAST': PRIORITY_LAST, 'WATCH':PRIORITY_WATCH},
3637
NOOP = 'noop',
3738
NG_EXCEPTION = 'ng-exception',
3839
NG_VALIDATION_ERROR = 'ng-validation-error',
@@ -501,17 +502,34 @@ function toJsonArray(buf, obj, pretty, stack){
501502
* bind to a new instance of elements. It also provides a list
502503
* of child paths which contain child templates
503504
*/
504-
function Template() {
505+
function Template(priority) {
505506
this.paths = [];
506507
this.children = [];
507508
this.inits = [];
509+
this.priority = priority || 0;
508510
}
509511

510512
Template.prototype = {
511513
init: function(element, scope) {
514+
var inits = {};
515+
this.collectInits(element, inits);
516+
foreachSorted(inits, function(queue){
517+
foreach(queue, function(fn){
518+
fn(scope);
519+
});
520+
});
521+
},
522+
523+
collectInits: function(element, inits) {
524+
var queue = inits[this.priority];
525+
if (!queue) {
526+
inits[this.priority] = queue = [];
527+
}
512528
element = jqLite(element);
513529
foreach(this.inits, function(fn) {
514-
scope.$tryEval(fn, element, element);
530+
queue.push(function(scope) {
531+
scope.$tryEval(fn, element, element);
532+
});
515533
});
516534

517535
var i,
@@ -520,7 +538,7 @@ Template.prototype = {
520538
paths = this.paths,
521539
length = paths.length;
522540
for (i = 0; i < length; i++) {
523-
children[i].init(childNodes[paths[i]], scope);
541+
children[i].collectInits(childNodes[paths[i]], inits);
524542
}
525543
},
526544

@@ -575,13 +593,13 @@ Compiler.prototype = {
575593
};
576594
},
577595

578-
templatize: function(element){
596+
templatize: function(element, priority){
579597
var self = this,
580598
widget,
581599
directiveFns = self.directives,
582600
descend = true,
583601
directives = true,
584-
template = new Template(),
602+
template,
585603
selfApi = {
586604
compile: bind(self, self.compile),
587605
comment:function(text) {return jqLite(document.createComment(text));},
@@ -590,7 +608,11 @@ Compiler.prototype = {
590608
descend: function(value){ if(isDefined(value)) descend = value; return descend;},
591609
directives: function(value){ if(isDefined(value)) directives = value; return directives;}
592610
};
593-
611+
priority = element.attr('ng-eval-order') || priority || 0;
612+
if (isString(priority)) {
613+
priority = PRIORITY[uppercase(priority)] || 0;
614+
}
615+
template = new Template(priority);
594616
eachAttribute(element, function(value, name){
595617
if (!widget) {
596618
if (widget = self.widgets['@' + name]) {
@@ -632,7 +654,7 @@ Compiler.prototype = {
632654
// Process non text child nodes
633655
if (descend) {
634656
eachNode(element, function(child, i){
635-
template.addChild(i, self.templatize(child));
657+
template.addChild(i, self.templatize(child, priority));
636658
});
637659
}
638660
return template.empty() ? null : template;
@@ -3339,6 +3361,8 @@ angularWidget('NG:SWITCH', function ngSwitch(element){
33393361
element.append(switchCase.element);
33403362
childScope.$tryEval(switchCase.change, element);
33413363
switchCase.template(switchCase.element, childScope);
3364+
if (scope.$invalidWidgets)
3365+
scope.$invalidWidgets.clearOrphans();
33423366
childScope.$init();
33433367
}
33443368
});
@@ -3491,6 +3515,21 @@ angularService("$invalidWidgets", function(){
34913515
});
34923516
return count;
34933517
};
3518+
invalidWidgets.clearOrphans = function() {
3519+
for(var i = 0; i < invalidWidgets.length;) {
3520+
var widget = invalidWidgets[i];
3521+
if (isOrphan(widget[0])) {
3522+
invalidWidgets.splice(i, 1);
3523+
} else {
3524+
i++;
3525+
}
3526+
}
3527+
};
3528+
function isOrphan(widget) {
3529+
if (widget == window.document) return false;
3530+
var parent = widget.parentNode;
3531+
return !parent || isOrphan(parent);
3532+
}
34943533
return invalidWidgets;
34953534
});
34963535
var browserSingleton;

src/services.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,20 @@ angularService("$invalidWidgets", function(){
115115
});
116116
return count;
117117
};
118+
invalidWidgets.clearOrphans = function() {
119+
for(var i = 0; i < invalidWidgets.length;) {
120+
var widget = invalidWidgets[i];
121+
if (isOrphan(widget[0])) {
122+
invalidWidgets.splice(i, 1);
123+
} else {
124+
i++;
125+
}
126+
}
127+
};
128+
function isOrphan(widget) {
129+
if (widget == window.document) return false;
130+
var parent = widget.parentNode;
131+
return !parent || isOrphan(parent);
132+
}
118133
return invalidWidgets;
119134
});

src/widgets.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ angularWidget('NG:SWITCH', function ngSwitch(element){
225225
element.append(switchCase.element);
226226
childScope.$tryEval(switchCase.change, element);
227227
switchCase.template(switchCase.element, childScope);
228+
if (scope.$invalidWidgets)
229+
scope.$invalidWidgets.clearOrphans();
228230
childScope.$init();
229231
}
230232
});

test/servicesSpec.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,22 @@ describe("service $invalidWidgets", function(){
8080
});
8181

8282
it("should count number of invalid widgets", function(){
83-
var scope = compile('<input name="price" ng-required></input>').$init();
83+
var scope = compile('<input name="price" ng-required ng-validate="number"></input>').$init();
8484
expect(scope.$invalidWidgets.length).toEqual(1);
8585
scope.price = 123;
8686
scope.$eval();
8787
expect(scope.$invalidWidgets.length).toEqual(0);
8888
scope.$element.remove();
89+
scope.price = 'abc';
90+
scope.$eval();
91+
expect(scope.$invalidWidgets.length).toEqual(1);
92+
93+
jqLite(document.body).append(scope.$element);
94+
scope.$invalidWidgets.clearOrphans();
95+
expect(scope.$invalidWidgets.length).toEqual(1);
96+
97+
jqLite(document.body).html('');
98+
scope.$invalidWidgets.clearOrphans();
99+
expect(scope.$invalidWidgets.length).toEqual(0);
89100
});
90101
});

test/widgetsSpec.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,15 @@ describe('ng:switch', function(){
221221

222222
it('should call init on switch', function(){
223223
var scope = compile('<ng:switch on="url" change="name=\'works\'"><div ng-switch-when="a">{{name}}</div></ng:include>');
224+
var cleared = false;
224225
scope.url = 'a';
226+
scope.$invalidWidgets = {clearOrphans: function(){
227+
cleared = true;
228+
}};
225229
scope.$init();
226230
expect(scope.name).toEqual(undefined);
227231
expect(scope.$element.text()).toEqual('works');
232+
expect(cleared).toEqual(true);
228233
});
229234
});
230235

0 commit comments

Comments
 (0)