Search code examples
javascriptangularjscomparecoercion

Implementing JavaScript function areDifferent(oldValue, newValue) to compare emptiness human-like style


I'm getting and object from the back-end with some properties and use AngularJS to put them into input fields (inputs, textareas, checkboxes, dropdown lists).

These properties are in some cases a text value, in some a number value but can also be null, undefined, false or "".

I clone this object and then check if user is making any modifications to each of these values by comparing the old (stored) value with new (current) one.

I don't want to use the ng-dirty class for detecting a change because it does not disappear when you go back to the previous value after a prior modification (e.g. when using Ctrl+Z).

I thought this task would be simple however I'm getting trouble with this due to ambiguous nature of JS values.

Of course I treat every of these:

  • null
  • undefined
  • false
  • ""

an "empty value" because for user "an empty field is an empty field", regardless of what the model stores underneath. So, for example, a change from undefined to "" is not really a change.

So far I've got this:

$scope.areDifferent = function (oldValue, newValue) {

    var a = true, b = true;

    if (oldValue === null ||
       oldValue === undefined ||
       oldValue === false ||
       oldValue === "") {
        a = false; 
    }

    if (newValue === null ||
       newValue === undefined ||
       newValue === false ||
       newValue === "") {
        b = false; 
    }

    if (!a && !b) {
        return false; // both values are "empty"
    }
    else if (a != b) {
        return true; // one of the values is "non-empty"
    }
    else {
        return oldValue != newValue; // compare the value of "non-empty" properties
    }
}

But I'm curious if this is correct (are there any non-covered edge cases?) and if it can be simplified, because I know that in JS there are some useful shorthand coding techniques like:

  • a || ''
  • if(a)
  • if(a.length)
  • if(a == null)

I've tried to use them here but it only leads to frustration because there is always an edge case which is not covered. Any help appreciated.


Solution

  • You could use exclusive OR and check the values with

    if (!oldValue && newValue || oldValue && !newValue) {
        // update
    }
    

    that means, if either oldValue is truthy and newValue is falsy or oldValue is falsy and newValue is truthy then make an update of the data.

    An extended check for same type and changes.

    if (!oldValue && newValue || oldValue && !newValue || typeof oldValue === typeof newValue && oldValue !== newValue) {
        // update
    }