fix($parse): respect the interceptor.$stateful flag
This commit is contained in:
+24
-20
@@ -1798,15 +1798,9 @@ function $ParseProvider() {
|
||||
var lexer = new Lexer($parseOptions);
|
||||
var parser = new Parser(lexer, $filter, $parseOptions);
|
||||
parsedExpression = parser.parse(exp);
|
||||
if (parsedExpression.constant) {
|
||||
parsedExpression.$$watchDelegate = constantWatchDelegate;
|
||||
} else if (oneTime) {
|
||||
parsedExpression.oneTime = true;
|
||||
parsedExpression.$$watchDelegate = oneTimeWatchDelegate;
|
||||
} else if (parsedExpression.inputs) {
|
||||
parsedExpression.$$watchDelegate = inputsWatchDelegate;
|
||||
}
|
||||
cache[cacheKey] = parsedExpression;
|
||||
parsedExpression.oneTime = !!oneTime;
|
||||
|
||||
cache[cacheKey] = addWatchDelegate(parsedExpression);
|
||||
}
|
||||
return addInterceptor(parsedExpression, interceptorFn);
|
||||
|
||||
@@ -1931,9 +1925,21 @@ function $ParseProvider() {
|
||||
return unwatch;
|
||||
}
|
||||
|
||||
function addWatchDelegate(parsedExpression) {
|
||||
if (parsedExpression.constant) {
|
||||
parsedExpression.$$watchDelegate = constantWatchDelegate;
|
||||
} else if (parsedExpression.oneTime) {
|
||||
parsedExpression.$$watchDelegate = oneTimeWatchDelegate;
|
||||
} else if (parsedExpression.inputs) {
|
||||
parsedExpression.$$watchDelegate = inputsWatchDelegate;
|
||||
}
|
||||
|
||||
return parsedExpression;
|
||||
}
|
||||
|
||||
function addInterceptor(parsedExpression, interceptorFn) {
|
||||
if (!interceptorFn) return parsedExpression;
|
||||
var watchDelegate = parsedExpression.$$watchDelegate;
|
||||
|
||||
var useInputs = false;
|
||||
|
||||
var isDone = parsedExpression.literal ? isAllDefined : isDefined;
|
||||
@@ -1953,18 +1959,16 @@ function $ParseProvider() {
|
||||
|
||||
var fn = parsedExpression.oneTime ? oneTimeInterceptedExpression : regularInterceptedExpression;
|
||||
|
||||
// Propogate the literal/oneTime attributes
|
||||
// Propogate the literal/oneTime/constant attributes
|
||||
fn.literal = parsedExpression.literal;
|
||||
fn.oneTime = parsedExpression.oneTime;
|
||||
fn.constant = parsedExpression.constant;
|
||||
|
||||
// Propagate or create inputs / $$watchDelegates
|
||||
useInputs = !parsedExpression.inputs;
|
||||
if (watchDelegate && watchDelegate !== inputsWatchDelegate) {
|
||||
fn.$$watchDelegate = watchDelegate;
|
||||
fn.inputs = parsedExpression.inputs;
|
||||
} else if (!interceptorFn.$stateful) {
|
||||
// Treat interceptor like filters - assume non-stateful by default and use the inputsWatchDelegate
|
||||
fn.$$watchDelegate = inputsWatchDelegate;
|
||||
// Treat the interceptor like filters.
|
||||
// If it is not $stateful then only watch its inputs.
|
||||
// If the expression itself has no inputs then use the full expression as an input.
|
||||
if (!interceptorFn.$stateful) {
|
||||
useInputs = !parsedExpression.inputs;
|
||||
fn.inputs = (parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression]).map(function(e) {
|
||||
// Remove the isPure flag of inputs when it is not absolute because they are now wrapped in a
|
||||
// potentially non-pure interceptor function.
|
||||
@@ -1975,7 +1979,7 @@ function $ParseProvider() {
|
||||
});
|
||||
}
|
||||
|
||||
return fn;
|
||||
return addWatchDelegate(fn);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -3324,6 +3324,72 @@ describe('parser', function() {
|
||||
expect(called).toBe(true);
|
||||
}));
|
||||
|
||||
it('should always be invoked if flagged as $stateful when wrapping one-time',
|
||||
inject(function($parse) {
|
||||
|
||||
var interceptorCalls = 0;
|
||||
function interceptor() {
|
||||
interceptorCalls++;
|
||||
return 123;
|
||||
}
|
||||
interceptor.$stateful = true;
|
||||
|
||||
scope.$watch($parse('::a', interceptor));
|
||||
|
||||
interceptorCalls = 0;
|
||||
scope.$digest();
|
||||
expect(interceptorCalls).not.toBe(0);
|
||||
|
||||
interceptorCalls = 0;
|
||||
scope.$digest();
|
||||
expect(interceptorCalls).not.toBe(0);
|
||||
}));
|
||||
|
||||
it('should always be invoked if flagged as $stateful when wrapping one-time with inputs',
|
||||
inject(function($parse) {
|
||||
|
||||
$filterProvider.register('identity', valueFn(identity));
|
||||
|
||||
var interceptorCalls = 0;
|
||||
function interceptor() {
|
||||
interceptorCalls++;
|
||||
return 123;
|
||||
}
|
||||
interceptor.$stateful = true;
|
||||
|
||||
scope.$watch($parse('::a | identity', interceptor));
|
||||
|
||||
interceptorCalls = 0;
|
||||
scope.$digest();
|
||||
expect(interceptorCalls).not.toBe(0);
|
||||
|
||||
interceptorCalls = 0;
|
||||
scope.$digest();
|
||||
expect(interceptorCalls).not.toBe(0);
|
||||
}));
|
||||
|
||||
it('should always be invoked if flagged as $stateful when wrapping one-time literal',
|
||||
inject(function($parse) {
|
||||
|
||||
var interceptorCalls = 0;
|
||||
function interceptor() {
|
||||
interceptorCalls++;
|
||||
return 123;
|
||||
}
|
||||
interceptor.$stateful = true;
|
||||
|
||||
scope.$watch($parse('::[a]', interceptor));
|
||||
|
||||
// Would be great if interceptor-output was checked for changes and this didn't throw...
|
||||
interceptorCalls = 0;
|
||||
expect(function() { scope.$digest(); }).toThrowMinErr('$rootScope', 'infdig');
|
||||
expect(interceptorCalls).not.toBe(0);
|
||||
|
||||
interceptorCalls = 0;
|
||||
expect(function() { scope.$digest(); }).toThrowMinErr('$rootScope', 'infdig');
|
||||
expect(interceptorCalls).not.toBe(0);
|
||||
}));
|
||||
|
||||
it('should not be invoked unless the input changes', inject(function($parse) {
|
||||
var called = false;
|
||||
function interceptor(v) {
|
||||
@@ -3434,6 +3500,29 @@ describe('parser', function() {
|
||||
scope.$digest();
|
||||
expect(scope.$$watchersCount).toBe(0);
|
||||
}));
|
||||
|
||||
it('should not propogate $$watchDelegate to the interceptor wrapped expression', inject(function($parse) {
|
||||
function getter(s) {
|
||||
return s.x;
|
||||
}
|
||||
getter.$$watchDelegate = getter;
|
||||
|
||||
function doubler(v) {
|
||||
return 2 * v;
|
||||
}
|
||||
|
||||
var lastValue;
|
||||
function watcher(val) {
|
||||
lastValue = val;
|
||||
}
|
||||
scope.$watch($parse(getter, doubler), watcher);
|
||||
|
||||
scope.$apply('x = 1');
|
||||
expect(lastValue).toBe(2 * 1);
|
||||
|
||||
scope.$apply('x = 123');
|
||||
expect(lastValue).toBe(2 * 123);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('literals', function() {
|
||||
|
||||
Reference in New Issue
Block a user