diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js
index 6f3919dfb174..a4e09f0dc588 100644
--- a/src/ng/directive/input.js
+++ b/src/ng/directive/input.js
@@ -385,7 +385,9 @@ var inputType = {
function isEmpty(value) {
- return isUndefined(value) || value === '' || value === null || value !== value;
+ return isUndefined(value) || value === '' || value === null ||
+ (value.length === 0 && isArrayLike(value)) ||
+ value !== value;
}
@@ -1082,11 +1084,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
// model -> value
var ctrl = this;
- $scope.$watch(function ngModelWatch() {
+ $scope.$watchCollection($attr.ngModel, function ngModelWatch(newValue, oldValue) {
var value = ngModelGet($scope);
// if scope model value and ngModel value are out of sync
- if (ctrl.$modelValue !== value) {
+ if (!equals(ctrl.$modelValue, oldValue)) {
var formatters = ctrl.$formatters,
idx = formatters.length;
diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js
index a62f706c52da..296491bcef4f 100644
--- a/src/ng/directive/select.js
+++ b/src/ng/directive/select.js
@@ -266,7 +266,6 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
}
function Multiple(scope, selectElement, ctrl) {
- var lastView;
ctrl.$render = function() {
var items = new HashMap(ctrl.$viewValue);
forEach(selectElement.find('option'), function(option) {
@@ -274,13 +273,10 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
});
};
- // we have to do it on each watch since ngModel watches reference, but
- // we need to work of an array, so we need to see if anything was inserted/removed
- scope.$watch(function selectMultipleWatch() {
- if (!equals(lastView, ctrl.$viewValue)) {
- lastView = copy(ctrl.$viewValue);
- ctrl.$render();
- }
+ scope.$watchCollection(attr.ngModel, function selectMultipleWatch(newValue, oldValue) {
+ ctrl.$viewValue = newValue;
+ requiredValidator && requiredValidator(newValue);
+ ctrl.$render();
});
selectElement.on('change', function() {
diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js
index d3b2762d8c01..22e7787c9707 100644
--- a/src/ng/rootScope.js
+++ b/src/ng/rootScope.js
@@ -362,6 +362,7 @@ function $RootScopeProvider(){
$watchCollection: function(obj, listener) {
var self = this;
var oldValue;
+ var oldArray;
var newValue;
var changeDetected = 0;
var objGetter = $parse(obj);
@@ -371,6 +372,7 @@ function $RootScopeProvider(){
function $watchCollectionWatch() {
newValue = objGetter(self);
+ oldArray = null;
var newLength, key;
if (!isObject(newValue)) {
@@ -386,6 +388,8 @@ function $RootScopeProvider(){
changeDetected++;
}
+ oldArray = oldValue.slice(0);
+
newLength = newValue.length;
if (oldLength !== newLength) {
@@ -439,7 +443,7 @@ function $RootScopeProvider(){
}
function $watchCollectionAction() {
- listener(newValue, oldValue, self);
+ listener(newValue, oldArray || oldValue, self);
}
return this.$watch($watchCollectionWatch, $watchCollectionAction);
diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js
index facc2b806bc9..814c72ec9a3a 100644
--- a/test/ng/directive/inputSpec.js
+++ b/test/ng/directive/inputSpec.js
@@ -986,7 +986,7 @@ describe('input', function() {
expect(scope.list).toEqual(['a']);
changeInputValueTo('a , b');
- expect(inputElm.val()).toEqual('a , b');
+ expect(inputElm.val()).toEqual('a, b');
expect(scope.list).toEqual(['a', 'b']);
});
@@ -1019,6 +1019,28 @@ describe('input', function() {
changeInputValueTo('a,b: c');
expect(scope.list).toEqual(['a', 'b', 'c']);
});
+
+ it("should detect changes in the values of an array", function () {
+ var list = ['x', 'y', 'z'];
+ compileInput('');
+ scope.$apply(function() {
+ scope.list = list;
+ });
+ expect(inputElm.val()).toBe('x, y, z');
+ scope.$apply(function() {
+ list.unshift('w');
+ });
+ expect(inputElm.val()).toBe('w, x, y, z');
+ });
+
+ it('should be invalid if empty', function() {
+ compileInput('');
+ changeInputValueTo('a');
+ expect(inputElm).toBeValid();
+ changeInputValueTo('');
+ expect(inputElm).toBeInvalid();
+ });
+
});
describe('required', function() {
diff --git a/test/ng/rootScopeSpec.js b/test/ng/rootScopeSpec.js
index 656385e9681c..83b49bead4c1 100644
--- a/test/ng/rootScopeSpec.js
+++ b/test/ng/rootScopeSpec.js
@@ -510,6 +510,28 @@ describe('Scope', function() {
$rootScope.$digest();
expect(arrayLikelog).toEqual(['x', 'y']);
});
+
+ it('should return a new array with old values', function(){
+ var watchArgs;
+ $rootScope.$watchCollection('obj', function (newValues, oldValues) {
+ watchArgs = {
+ newValues: newValues,
+ oldValues: oldValues
+ };
+ });
+
+ $rootScope.obj = ['a'];
+ $rootScope.$digest();
+
+ expect(watchArgs.newValues).toEqual($rootScope.obj);
+ expect(watchArgs.oldValues).toEqual([]);
+
+ $rootScope.obj.push('b');
+ $rootScope.$digest();
+
+ expect(watchArgs.newValues).toEqual(['a', 'b']);
+ expect(watchArgs.oldValues).toEqual(['a']);
+ })
});