refactor(bindings): remove the decoration of the DOM with errors.

Only $exceptionHandler gets notified now.
This commit is contained in:
Misko Hevery 2011-08-24 21:50:12 -07:00 committed by Igor Minar
parent 1942861472
commit e86c435349
4 changed files with 25 additions and 98 deletions

View file

@ -8,17 +8,6 @@
color: red;
}
.ng-exception {
border: 2px solid #FF0000;
font-family: "Courier New", Courier, monospace;
font-size: smaller;
white-space: pre;
}
.ng-validation-error {
border: 2px solid #FF0000;
}
/*****************
* indicators
*****************/

View file

@ -71,8 +71,6 @@ var _undefined = undefined,
$value = 'value',
$selected = 'selected',
$undefined = 'undefined',
NG_EXCEPTION = 'ng-exception',
NG_VALIDATION_ERROR = 'ng-validation-error',
NOOP = 'noop',
Error = window.Error,
/** holds major version number for IE or NaN for real browsers */
@ -758,36 +756,6 @@ function setHtml(node, html) {
}
}
function isRenderableElement(element) {
var name = element && element[0] && element[0].nodeName;
return name && name.charAt(0) != '#' &&
!includes(['TR', 'COL', 'COLGROUP', 'TBODY', 'THEAD', 'TFOOT'], name);
}
function elementError(element, type, error) {
var parent;
while (!isRenderableElement(element)) {
parent = element.parent();
if (parent.length) {
element = element.parent();
} else {
return;
}
}
if (element[0]['$NG_ERROR'] !== error) {
element[0]['$NG_ERROR'] = error;
if (error) {
element.addClass(type);
element.attr(type, error.message || error);
} else {
element.removeClass(type);
element.removeAttr(type);
}
}
}
function concat(array1, array2, index) {
return array1.concat(slice.call(array2, index));
}

View file

@ -216,19 +216,39 @@ angularDirective("ng:bind", function(expression, element){
element.addClass('ng-binding');
var exprFn = parser(expression).statements();
return function(element) {
var lastValue = noop, lastError = noop;
var lastValue = Number.NaN;
this.$watch(function(scope) {
// TODO(misko): remove error handling https://github.com/angular/angular.js/issues/347
var error, value, html, isHtml, isDomElement,
var value, html, isHtml, isDomElement,
hadOwnElement = scope.hasOwnProperty('$element'),
oldElement = scope.$element;
// TODO(misko): get rid of $element https://github.com/angular/angular.js/issues/348
scope.$element = element;
try {
value = exprFn(scope);
// If we are HTML than save the raw HTML data so that we don't recompute sanitization since
// it is expensive.
// TODO(misko): turn this into a more generic way to compute this
if ((isHtml = (value instanceof HTML)))
value = (html = value).html;
if (lastValue === value) return;
isDomElement = isElement(value);
if (!isHtml && !isDomElement && isObject(value)) {
value = toJson(value, true);
}
if (value != lastValue) {
lastValue = value;
if (isHtml) {
element.html(html.get());
} else if (isDomElement) {
element.html('');
element.append(value);
} else {
element.text(value == undefined ? '' : value);
}
}
} catch (e) {
scope.$service('$exceptionHandler')(e);
error = formatError(e);
} finally {
if (hadOwnElement) {
scope.$element = oldElement;
@ -236,30 +256,6 @@ angularDirective("ng:bind", function(expression, element){
delete scope.$element;
}
}
// If we are HTML, then save the raw HTML data so that we don't
// recompute sanitization since that is expensive.
// TODO: turn this into a more generic way to compute this
if ((isHtml = (value instanceof HTML)))
value = (html = value).html;
if (lastValue === value && lastError == error) return;
isDomElement = isElement(value);
if (!isHtml && !isDomElement && isObject(value)) {
value = toJson(value, true);
}
if (value != lastValue || error != lastError) {
lastValue = value;
lastError = error;
elementError(element, NG_EXCEPTION, error);
if (error) value = error;
if (isHtml) {
element.html(html.get());
} else if (isDomElement) {
element.html('');
element.append(value);
} else {
element.text(value == undefined ? '' : value);
}
}
});
};
});
@ -272,20 +268,8 @@ function compileBindTemplate(template){
forEach(parseBindings(template), function(text){
var exp = binding(text);
bindings.push(exp
? function(scope, element) {
var error, value;
try {
value = scope.$eval(exp);
} catch(e) {
scope.$service('$exceptionHandler')(e);
error = toJson(e);
}
elementError(element, NG_EXCEPTION, error);
return error ? error : value;
}
: function() {
return text;
});
? function(scope, element) { return scope.$eval(exp); }
: function() { return text; });
});
bindTemplateCache[template] = fn = function(scope, element, prettyPrintJson) {
var parts = [],

View file

@ -270,39 +270,25 @@ describe('Binder', function(){
it('IfTextBindingThrowsErrorDecorateTheSpan', function(){
var scope = this.compile('<div>{{error.throw()}}</div>', null, true);
var doc = scope.$element;
var errorLogs = scope.$service('$exceptionHandler').errors;
scope.error = {
'throw': function(){throw "ErrorMsg1";}
};
scope.$apply();
var span = childNode(doc, 0);
assertTrue(span.hasClass('ng-exception'));
assertTrue(!!span.text().match(/ErrorMsg1/));
assertTrue(!!span.attr('ng-exception').match(/ErrorMsg1/));
assertEquals(['ErrorMsg1'], errorLogs.shift());
scope.error['throw'] = function(){throw "MyError";};
errorLogs.length = 0;
scope.$apply();
span = childNode(doc, 0);
assertTrue(span.hasClass('ng-exception'));
assertTrue(span.text(), span.text().match('MyError') !== null);
assertEquals('MyError', span.attr('ng-exception'));
assertEquals(['MyError'], errorLogs.shift());
scope.error['throw'] = function(){return "ok";};
scope.$apply();
assertFalse(span.hasClass('ng-exception'));
assertEquals('ok', span.text());
assertEquals(null, span.attr('ng-exception'));
assertEquals(0, errorLogs.length);
});
it('IfAttrBindingThrowsErrorDecorateTheAttribute', function(){
var scope = this.compile('<div attr="before {{error.throw()}} after"></div>', null, true);
var doc = scope.$element;
var errorLogs = scope.$service('$exceptionHandler').errors;
var count = 0;