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

Commit 712ece3

Browse files
committed
fix($parse): respect the interceptor.$stateful flag
1 parent b4651e5 commit 712ece3

File tree

2 files changed

+90
-22
lines changed

2 files changed

+90
-22
lines changed

src/ng/parse.js

+23-20
Original file line numberDiff line numberDiff line change
@@ -1795,15 +1795,9 @@ function $ParseProvider() {
17951795
var lexer = new Lexer($parseOptions);
17961796
var parser = new Parser(lexer, $filter, $parseOptions);
17971797
parsedExpression = parser.parse(exp);
1798-
if (parsedExpression.constant) {
1799-
parsedExpression.$$watchDelegate = constantWatchDelegate;
1800-
} else if (oneTime) {
1801-
parsedExpression.oneTime = true;
1802-
parsedExpression.$$watchDelegate = oneTimeWatchDelegate;
1803-
} else if (parsedExpression.inputs) {
1804-
parsedExpression.$$watchDelegate = inputsWatchDelegate;
1805-
}
1806-
cache[cacheKey] = parsedExpression;
1798+
parsedExpression.oneTime = !!oneTime;
1799+
1800+
cache[cacheKey] = addWatchDelegate(parsedExpression);
18071801
}
18081802
return addInterceptor(parsedExpression, interceptorFn);
18091803

@@ -1928,6 +1922,18 @@ function $ParseProvider() {
19281922
return unwatch;
19291923
}
19301924

1925+
function addWatchDelegate(parsedExpression) {
1926+
if (parsedExpression.constant) {
1927+
parsedExpression.$$watchDelegate = constantWatchDelegate;
1928+
} else if (parsedExpression.oneTime) {
1929+
parsedExpression.$$watchDelegate = oneTimeWatchDelegate;
1930+
} else if (parsedExpression.inputs) {
1931+
parsedExpression.$$watchDelegate = inputsWatchDelegate;
1932+
}
1933+
1934+
return parsedExpression;
1935+
}
1936+
19311937
function addInterceptor(parsedExpression, interceptorFn) {
19321938
if (!interceptorFn) return parsedExpression;
19331939
var watchDelegate = parsedExpression.$$watchDelegate;
@@ -1950,23 +1956,20 @@ function $ParseProvider() {
19501956

19511957
var fn = parsedExpression.oneTime ? oneTimeInterceptedExpression : regularInterceptedExpression;
19521958

1953-
// Propogate the literal/oneTime attributes
1959+
// Propogate the literal/oneTime/constant attributes
19541960
fn.literal = parsedExpression.literal;
19551961
fn.oneTime = parsedExpression.oneTime;
1962+
fn.constant = parsedExpression.constant;
19561963

1957-
// Propagate or create inputs / $$watchDelegates
1958-
useInputs = !parsedExpression.inputs;
1959-
if (watchDelegate && watchDelegate !== inputsWatchDelegate) {
1960-
fn.$$watchDelegate = watchDelegate;
1961-
fn.inputs = parsedExpression.inputs;
1962-
} else if (!interceptorFn.$stateful) {
1963-
// If there is an interceptor, but no watchDelegate then treat the interceptor like
1964-
// we treat filters - it is assumed to be a pure function unless flagged with $stateful
1965-
fn.$$watchDelegate = inputsWatchDelegate;
1964+
// Treat the interceptor like filters.
1965+
// If it is not $stateful then only watch its inputs.
1966+
// If the expression itself has no inputs then use the full expression as an input.
1967+
if (!interceptorFn.$stateful) {
1968+
useInputs = !parsedExpression.inputs;
19661969
fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
19671970
}
19681971

1969-
return fn;
1972+
return addWatchDelegate(fn);
19701973
}
19711974
}];
19721975
}

test/ng/parseSpec.js

+67-2
Original file line numberDiff line numberDiff line change
@@ -3233,8 +3233,7 @@ describe('parser', function() {
32333233

32343234
describe('interceptorFns', function() {
32353235

3236-
it('should always be invoked if they are flagged as having $stateful',
3237-
inject(function($parse) {
3236+
it('should always be invoked if flagged as $stateful', inject(function($parse) {
32383237
var called = false;
32393238
function interceptor() {
32403239
called = true;
@@ -3256,6 +3255,72 @@ describe('parser', function() {
32563255
expect(called).toBe(true);
32573256
}));
32583257

3258+
it('should always be invoked if flagged as $stateful when wrapping one-time',
3259+
inject(function($parse) {
3260+
3261+
var interceptorCalls = 0;
3262+
function interceptor() {
3263+
interceptorCalls++;
3264+
return 123;
3265+
}
3266+
interceptor.$stateful = true;
3267+
3268+
scope.$watch($parse('::a', interceptor));
3269+
3270+
interceptorCalls = 0;
3271+
scope.$digest();
3272+
expect(interceptorCalls).not.toBe(0);
3273+
3274+
interceptorCalls = 0;
3275+
scope.$digest();
3276+
expect(interceptorCalls).not.toBe(0);
3277+
}));
3278+
3279+
it('should always be invoked if flagged as $stateful when wrapping one-time with inputs',
3280+
inject(function($parse) {
3281+
3282+
$filterProvider.register('identity', valueFn(identity));
3283+
3284+
var interceptorCalls = 0;
3285+
function interceptor() {
3286+
interceptorCalls++;
3287+
return 123;
3288+
}
3289+
interceptor.$stateful = true;
3290+
3291+
scope.$watch($parse('::a | identity', interceptor));
3292+
3293+
interceptorCalls = 0;
3294+
scope.$digest();
3295+
expect(interceptorCalls).not.toBe(0);
3296+
3297+
interceptorCalls = 0;
3298+
scope.$digest();
3299+
expect(interceptorCalls).not.toBe(0);
3300+
}));
3301+
3302+
it('should always be invoked if flagged as $stateful when wrapping one-time literal',
3303+
inject(function($parse) {
3304+
3305+
var interceptorCalls = 0;
3306+
function interceptor() {
3307+
interceptorCalls++;
3308+
return 123;
3309+
}
3310+
interceptor.$stateful = true;
3311+
3312+
scope.$watch($parse('::[a]', interceptor));
3313+
3314+
// Would be great if interceptor-output was checked for changes and this didn't throw...
3315+
interceptorCalls = 0;
3316+
expect(function() { scope.$digest(); }).toThrowMinErr('$rootScope', 'infdig');
3317+
expect(interceptorCalls).not.toBe(0);
3318+
3319+
interceptorCalls = 0;
3320+
expect(function() { scope.$digest(); }).toThrowMinErr('$rootScope', 'infdig');
3321+
expect(interceptorCalls).not.toBe(0);
3322+
}));
3323+
32593324
it('should not be invoked unless the input changes', inject(function($parse) {
32603325
var called = false;
32613326
function interceptor(v) {

0 commit comments

Comments
 (0)