Equivalent of angular.equals in angular2

All we need is an easy explanation of the problem, so here it is.

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.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

@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

Method 2

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;
  }
}

Method 3

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));

Method 4

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;
}

Method 5

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

Method 6

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;
}

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply