mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
refactor(bindings): remove the decoration of the DOM with errors.
Only $exceptionHandler gets notified now.
This commit is contained in:
parent
1942861472
commit
e86c435349
4 changed files with 25 additions and 98 deletions
|
|
@ -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
|
||||
*****************/
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = [],
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue