CodeToad
CodeToad

Reputation: 4724

AngularJS : check if a model value has changed

IS there a way to check a dirty flag on the model itself, independent of the view?

I need the angular controller to know what properties have been changed, in order to only save changed variables to server.

I have implemented logic regarding if my entire form is dirty or pristine, but that is not specific enough

I could just slap a name and ng-form attribute on every input, to make it recognizable as a form in the controller, but then I end up with a controller that is strongly coupled with the view.

Another not-so appealing approach is to store the initial values that every input is bound to in a separate object, then compare the current values with the initial values to know if they have changed.

I checked Monitor specific fields for pristine/dirty form state and AngularJS : $pristine for ng-check checked inputs

Upvotes: 3

Views: 17774

Answers (3)

Philip Callender
Philip Callender

Reputation: 1485

The class shown below may work well for your purpose, and is easily reused across pages.

At the time you load your models, you remember their original values:

    $scope.originalValues = new OriginalValues();

    // Set the model and remember it's value
    $scope.someobject = ...
    var key = 'type-' + $scope.someobject.some_unique_key;
    $scope.originalValues.remember(key, $scope.someobject);

Later you can determine if it needs to be saved using:

    var key = 'type-' + $scope.someobject.some_unique_key;
    if ($scope.originalValues.changed(key, $scope.someobject)) {
       // Save someobject
       ...
    }

The key allows you to remember the original values for multiple models. If you only have one ng-model the key can simply be 'model' or any other string.

The assumption is that properties starting with '$' or '_' should be ignored when looking for changes, and that new properties will not be added by the UI.

Here's the class definition:

function OriginalValues() {
    var hashtable = [ ]; // name -> json

    return {

      // Remember an object returned by the API
      remember: function(key, object) {
        // Create a clone, without system properties.
        var newobj = { };
        for (var property in object) {
          if (object.hasOwnProperty(property) && !property.startsWith('_') && !property.startsWith('$')) {
            newobj[property] = object[property];
          }
        }
        hashtable[key] = newobj;
      },// remember

      // See if this object matches the original
      changed: function(key, object) {
        if (!object) {
          return false; // Object does not exist
        }

        var original = hashtable[key];
        if (!original) {
          return true; // New object
        }

        // Compare against the original
        for (var property in original) {
          var changed = false;
          if (object[property] !== original[property]) {
            return true; // Property has changed
          }
        }
        return false;
      }// changed

    }; // returned object
  } // OriginalValues

Upvotes: 0

Philip Callender
Philip Callender

Reputation: 1485

You may find it easiest to store and later compare against the JSON representation of the object, rather than looping through the various properties.

See Detect unsaved data using angularjs.

Upvotes: 0

Mothupally
Mothupally

Reputation: 780

One option I could think of is

  1. As you get a model/object from service, create a replica of the model within the model and bind this new model to your view.

  2. Add a watch on the new Model and as the model changes, use the replica to compare old and new models as follows

    var myModel = {
        property1: "Property1",
        property2: "Property2",
        array1:["1","2","3"]
    }
    var getModel = function(myModel){
       var oldData = {};
       for(var prop in myModel){
          oldData.prop = myModel[prop];
       }
       myModel.oldData = oldData;
       return myModel;
    }
    var getPropChanged = function(myModel){
      var oldData = myModel.oldData;
      for(var prop in myModel){
       if(prop !== "oldData"){
        if(myModel[prop] !== oldData[prop]){
            return{
                propChanged: prop,
                oldValue:oldData[prop],
                newValue:myModel[prop]
            }
          }
        }
      }
    }
    

Upvotes: 2

Related Questions