Angular 1.5 component track object changes

556 views Asked by At

I have an angular 1.5 (with components) app. In one of the components I have a local object defined as:

model.user = {
  firstName: 'John',
  lastName: 'Smith'
}

then in the markup I use it as:

<input class="field" ng-model="model.user.firstName" />

What I would like to do is to track when the user makes a change to this field and record the event. I spent some time looking at different options, but I wanted to ask what the suggested approach is when using components. Here is what I found so far:

  • $watch(...) - this works well because I get the old and new values, but it appears that this approach is discouraged.
  • $onChanges - this would not work because this is a local object.
  • $doCheck - this could potentially work, but I do not get any information on the changed object. I have to manually track the previous value.
  • ng-change - this would work, but I have a lot of fields and maintaining the markup may become a little difficult.

I am looking for an approach like Telerik's kendo MVVM. There I can bind the change event of any object to a function and retrieve the field that was changed, the old, and the new value. The beauty of this approach is that if my object changes, I do not have to make any changes to my code, the change event will pick up the new field without me having to write any code. Much cleaner and easier to maintain.

Is this possible in angular 1.5 with components? If so, what is the recommended approach?

Thank you.

1

There are 1 answers

0
dpdragnev On BEST ANSWER

As @CShark suggested, the ng-change method was the best option. To keep it less verbose in the markup I created a custom attribute directive that injects the ng-model-options and ng-change attributes:

module.directive('inputChanged', function ($compile) {
        function link(scope, element, attrs) {
            var field = attrs.ngModel;
            if (field) {
                element.removeAttr('input-changed');
                element.attr('ng-model-options', "{ updateOn: 'blur' }");
                var fn = "model.changed('" + field + "', " + field + ", '{{ " + field + " }}')";
                element.attr('ng-change', fn);

                $compile(element)(scope);
            }    
        }

        return {
            restrict: 'A',
            link: link,
            terminal: true,
            priority: 1000
        }
    });

In my model I have:

model.changed = function (field, newValue, oldValue) {
  //log the change
}

After this is done, just add the input-changed attribute to any element that has the ng-model attribute. E.g.

<input ng-model="model.user.firstName.value" input-changed />

Note that I am only capturing the change once the user have committed the change by setting the ng-model-options. Also notice that I am passing both the old and the new values to the model.changed function. This way I can acieve a $watch-like functionality without actually using a $watch.

I am not sure if this is the best solution, but it will do in my scenario.