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

Commit 724819e

Browse files
bripkensIgorMinar
authored andcommitted
fix(angular.equals): add support for regular expressions
Regular expression objects didn't used to be considered to be equal when using 'angular.equals'. Dirty checking therefore failed to recognize a property modification. Closes #2685
1 parent 32f8a04 commit 724819e

File tree

2 files changed

+49
-4
lines changed

2 files changed

+49
-4
lines changed

src/Angular.js

+21-4
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,18 @@ function isArray(value) {
413413
function isFunction(value){return typeof value == 'function';}
414414

415415

416+
/**
417+
* Determines if a value is a regular expression object.
418+
*
419+
* @private
420+
* @param {*} value Reference to check.
421+
* @returns {boolean} True if `value` is a `RegExp`.
422+
*/
423+
function isRegExp(value) {
424+
return toString.apply(value) == '[object RegExp]';
425+
}
426+
427+
416428
/**
417429
* Checks if `obj` is a window object.
418430
*
@@ -646,14 +658,17 @@ function shallowCopy(src, dst) {
646658
* @function
647659
*
648660
* @description
649-
* Determines if two objects or two values are equivalent. Supports value types, arrays and
661+
* Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and
650662
* objects.
651663
*
652664
* Two objects or values are considered equivalent if at least one of the following is true:
653665
*
654666
* * Both objects or values pass `===` comparison.
655667
* * Both objects or values are of the same type and all of their properties pass `===` comparison.
656668
* * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
669+
* * Both values represent the same regular expression (In JavasScript,
670+
* /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
671+
* representation matches).
657672
*
658673
* During a property comparison, properties of `function` type and properties with names
659674
* that begin with `$` are ignored.
@@ -680,6 +695,8 @@ function equals(o1, o2) {
680695
}
681696
} else if (isDate(o1)) {
682697
return isDate(o2) && o1.getTime() == o2.getTime();
698+
} else if (isRegExp(o1) && isRegExp(o2)) {
699+
return o1.toString() == o2.toString();
683700
} else {
684701
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
685702
keySet = {};
@@ -949,9 +966,9 @@ function encodeUriQuery(val, pctEncodeSpaces) {
949966
* one ngApp directive can be used per HTML document. The directive
950967
* designates the root of the application and is typically placed
951968
* at the root of the page.
952-
*
953-
* The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an
954-
* HTML document you must manually bootstrap them using {@link angular.bootstrap}.
969+
*
970+
* The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an
971+
* HTML document you must manually bootstrap them using {@link angular.bootstrap}.
955972
* Applications cannot be nested.
956973
*
957974
* In the example below if the `ngApp` directive would not be placed

test/AngularSpec.js

+28
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,17 @@ describe('angular', function() {
278278
expect(equals({}, {hasOwnProperty: 1})).toBe(false);
279279
expect(equals({}, {toString: null})).toBe(false);
280280
});
281+
282+
it('should compare regular expressions', function() {
283+
expect(equals(/abc/, /abc/)).toBe(true);
284+
expect(equals(/abc/i, new RegExp('abc', 'i'))).toBe(true);
285+
expect(equals(new RegExp('abc', 'i'), new RegExp('abc', 'i'))).toBe(true);
286+
expect(equals(new RegExp('abc', 'i'), new RegExp('abc'))).toBe(false);
287+
expect(equals(/abc/i, /abc/)).toBe(false);
288+
expect(equals(/abc/, /def/)).toBe(false);
289+
expect(equals(/^abc/, /abc/)).toBe(false);
290+
expect(equals(/^abc/, '/^abc/')).toBe(false);
291+
});
281292
});
282293

283294
describe('size', function() {
@@ -654,6 +665,23 @@ describe('angular', function() {
654665
});
655666
});
656667

668+
669+
describe('isRegExp', function() {
670+
it('should return true for RegExp object', function() {
671+
expect(isRegExp(/^foobar$/)).toBe(true);
672+
expect(isRegExp(new RegExp('^foobar$/'))).toBe(true);
673+
});
674+
675+
it('should return false for non RegExp objects', function() {
676+
expect(isRegExp([])).toBe(false);
677+
expect(isRegExp('')).toBe(false);
678+
expect(isRegExp(23)).toBe(false);
679+
expect(isRegExp({})).toBe(false);
680+
expect(isRegExp(new Date())).toBe(false);
681+
});
682+
});
683+
684+
657685
describe('compile', function() {
658686
it('should link to existing node and create scope', inject(function($rootScope, $compile) {
659687
var template = angular.element('<div>{{greeting = "hello world"}}</div>');

0 commit comments

Comments
 (0)