feat($parse): allow watching array/object of inputs to literal values
The inputs of array/object literals are now watched for changes. If the an input changes then a new instance of the literal will be provided when the parsed expression is executed. Closes #15301
This commit is contained in:
committed by
Peter Bacon Darwin
parent
7019d9f27a
commit
7084deccaa
+4
-4
@@ -1782,13 +1782,13 @@ function $ParseProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
function expressionInputDirtyCheck(newValue, oldValueOfValue) {
|
||||
function expressionInputDirtyCheck(newValue, oldValueOfValue, compareObjectIdentity) {
|
||||
|
||||
if (newValue == null || oldValueOfValue == null) { // null/undefined
|
||||
return newValue === oldValueOfValue;
|
||||
}
|
||||
|
||||
if (typeof newValue === 'object') {
|
||||
if (typeof newValue === 'object' && !compareObjectIdentity) {
|
||||
|
||||
// attempt to convert the value to a primitive type
|
||||
// TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
|
||||
@@ -1817,7 +1817,7 @@ function $ParseProvider() {
|
||||
inputExpressions = inputExpressions[0];
|
||||
return scope.$watch(function expressionInputWatch(scope) {
|
||||
var newInputValue = inputExpressions(scope);
|
||||
if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
|
||||
if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, parsedExpression.literal)) {
|
||||
lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
|
||||
oldInputValueOf = newInputValue && getValueOf(newInputValue);
|
||||
}
|
||||
@@ -1837,7 +1837,7 @@ function $ParseProvider() {
|
||||
|
||||
for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
|
||||
var newInputValue = inputExpressions[i](scope);
|
||||
if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
|
||||
if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], parsedExpression.literal))) {
|
||||
oldInputValues[i] = newInputValue;
|
||||
oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
|
||||
}
|
||||
|
||||
@@ -3118,6 +3118,74 @@ describe('parser', function() {
|
||||
scope.$digest();
|
||||
expect(objB.value).toBe(scope.input);
|
||||
}));
|
||||
|
||||
it('should support watching literals', inject(function($parse) {
|
||||
var lastVal = NaN;
|
||||
var callCount = 0;
|
||||
var listener = function(val) { callCount++; lastVal = val; };
|
||||
|
||||
scope.$watch('{val: val}', listener);
|
||||
|
||||
scope.$apply('val = 1');
|
||||
expect(callCount).toBe(1);
|
||||
expect(lastVal).toEqual({val: 1});
|
||||
|
||||
scope.$apply('val = []');
|
||||
expect(callCount).toBe(2);
|
||||
expect(lastVal).toEqual({val: []});
|
||||
|
||||
scope.$apply('val = []');
|
||||
expect(callCount).toBe(3);
|
||||
expect(lastVal).toEqual({val: []});
|
||||
|
||||
scope.$apply('val = {}');
|
||||
expect(callCount).toBe(4);
|
||||
expect(lastVal).toEqual({val: {}});
|
||||
}));
|
||||
|
||||
it('should only watch the direct inputs to literals', inject(function($parse) {
|
||||
var lastVal = NaN;
|
||||
var callCount = 0;
|
||||
var listener = function(val) { callCount++; lastVal = val; };
|
||||
|
||||
scope.$watch('{val: val}', listener);
|
||||
|
||||
scope.$apply('val = 1');
|
||||
expect(callCount).toBe(1);
|
||||
expect(lastVal).toEqual({val: 1});
|
||||
|
||||
scope.$apply('val = [2]');
|
||||
expect(callCount).toBe(2);
|
||||
expect(lastVal).toEqual({val: [2]});
|
||||
|
||||
scope.$apply('val.push(3)');
|
||||
expect(callCount).toBe(2);
|
||||
|
||||
scope.$apply('val.length = 0');
|
||||
expect(callCount).toBe(2);
|
||||
}));
|
||||
|
||||
it('should only watch the direct inputs to nested literals', inject(function($parse) {
|
||||
var lastVal = NaN;
|
||||
var callCount = 0;
|
||||
var listener = function(val) { callCount++; lastVal = val; };
|
||||
|
||||
scope.$watch('[{val: [val]}]', listener);
|
||||
|
||||
scope.$apply('val = 1');
|
||||
expect(callCount).toBe(1);
|
||||
expect(lastVal).toEqual([{val: [1]}]);
|
||||
|
||||
scope.$apply('val = [2]');
|
||||
expect(callCount).toBe(2);
|
||||
expect(lastVal).toEqual([{val: [[2]]}]);
|
||||
|
||||
scope.$apply('val.push(3)');
|
||||
expect(callCount).toBe(2);
|
||||
|
||||
scope.$apply('val.length = 0');
|
||||
expect(callCount).toBe(2);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('locals', function() {
|
||||
|
||||
Reference in New Issue
Block a user