Reputation: 1289
I am working on migration of angular 1 project to angular 2 . In angular 1 project I was using angular.equals for object comparison angular.equals($ctrl.obj1, $ctrl.newObj);
, I searched online for equivalent method in angular 2 but could not find any matching result.
Upvotes: 39
Views: 57209
Reputation: 1289
@Günter Yes you are right there is no equivalent in angular2 . While searching more I found third party library lodash which will do same job as angular.equals and syntax is same as angular one and this library solves my problem
Code example from lodash documentation
var object = { 'a': 1 };
var other = { 'a': 1 };
_.isEqual(object, other);
// => true
object === other;
// => false
Upvotes: 25
Reputation: 313
You could just copy the original source code from angularjs for the angular.equals function. Usage: equals(obj1, obj2);
var toString = Object.prototype.toString;
function isDefined(value) {return typeof value !== 'undefined';}
function isFunction(value) {return typeof value === 'function';}
function createMap() {
return Object.create(null);
}
function isWindow(obj) {
return obj && obj.window === obj;
}
function isScope(obj) {
return obj && obj.$evalAsync && obj.$watch;
}
function isRegExp(value) {
return toString.call(value) === '[object RegExp]';
}
function simpleCompare(a, b) { return a === b || (a !== a && b !== b); }
function isDate(value) {
return toString.call(value) === '[object Date]';
}
function isArray(arr) {
return Array.isArray(arr) || arr instanceof Array;
}
function equals(o1, o2) {
if (o1 === o2) return true;
if (o1 === null || o2 === null) return false;
// eslint-disable-next-line no-self-compare
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
if (t1 === t2 && t1 === 'object') {
if (isArray(o1)) {
if (!isArray(o2)) return false;
if ((length = o1.length) === o2.length) {
for (key = 0; key < length; key++) {
if (!equals(o1[key], o2[key])) return false;
}
return true;
}
} else if (isDate(o1)) {
if (!isDate(o2)) return false;
return simpleCompare(o1.getTime(), o2.getTime());
} else if (isRegExp(o1)) {
if (!isRegExp(o2)) return false;
return o1.toString() === o2.toString();
} else {
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
keySet = createMap();
for (key in o1) {
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
if (!equals(o1[key], o2[key])) return false;
keySet[key] = true;
}
for (key in o2) {
if (!(key in keySet) &&
key.charAt(0) !== '$' &&
isDefined(o2[key]) &&
!isFunction(o2[key])) return false;
}
return true;
}
}
return false;
}
Upvotes: 3
Reputation: 195
a = { name: 'me' }
b = { name: 'me' }
a == b // false
a === b // false
JSON.stringify(a) == JSON.stringify(b) // true
JSON.stringify(a) === JSON.stringify(b) // true
Upvotes: 1
Reputation: 7597
I rewrote Ariels answer (thank you!) to be TSLINT-friendly. You can also save some continues by using else if, but I think this is more clear. Maybe someone else needs it too:
export function deepEquals(x, y) {
if (x === y) {
return true; // if both x and y are null or undefined and exactly the same
} else if (!(x instanceof Object) || !(y instanceof Object)) {
return false; // if they are not strictly equal, they both need to be Objects
} else if (x.constructor !== y.constructor) {
// they must have the exact same prototype chain, the closest we can do is
// test their constructor.
return false;
} else {
for (const p in x) {
if (!x.hasOwnProperty(p)) {
continue; // other properties were tested using x.constructor === y.constructor
}
if (!y.hasOwnProperty(p)) {
return false; // allows to compare x[ p ] and y[ p ] when set to undefined
}
if (x[p] === y[p]) {
continue; // if they have the same strict value or identity then they are equal
}
if (typeof (x[p]) !== 'object') {
return false; // Numbers, Strings, Functions, Booleans must be strictly equal
}
if (!deepEquals(x[p], y[p])) {
return false;
}
}
for (const p in y) {
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p)) {
return false;
}
}
return true;
}
}
Upvotes: 22
Reputation: 1545
Instead of writing a function to iterate through the objects, you could just use JSON.stringify and compare the two strings?
Example:
var obj1 = {
title: 'title1',
tags: []
}
var obj2 = {
title: 'title1',
tags: ['r']
}
console.log(JSON.stringify(obj1));
console.log(JSON.stringify(obj2));
console.log(JSON.stringify(obj1) === JSON.stringify(obj2));
Upvotes: 9
Reputation: 1346
In Angular 2 you should use pure JavaScript/TypeScript for that so you can add this method to some service
private static equals(x, y) {
if (x === y)
return true;
// if both x and y are null or undefined and exactly the same
if (!(x instanceof Object) || !(y instanceof Object))
return false;
// if they are not strictly equal, they both need to be Objects
if (x.constructor !== y.constructor)
return false;
// they must have the exact same prototype chain, the closest we can do is
// test there constructor.
let p;
for (p in x) {
if (!x.hasOwnProperty(p))
continue;
// other properties were tested using x.constructor === y.constructor
if (!y.hasOwnProperty(p))
return false;
// allows to compare x[ p ] and y[ p ] when set to undefined
if (x[p] === y[p])
continue;
// if they have the same strict value or identity then they are equal
if (typeof (x[p]) !== "object")
return false;
// Numbers, Strings, Functions, Booleans must be strictly equal
if (!RXBox.equals(x[p], y[p]))
return false;
}
for (p in y) {
if (y.hasOwnProperty(p) && !x.hasOwnProperty(p))
return false;
}
return true;
}
Upvotes: 4