oikonomiyaki
oikonomiyaki

Reputation: 7951

Using scope.$watch to observe when a function executes

Suppose I have a custom directive, named my-directive, that has the default scope settings (scope: false, which means it shares the scope of the (parent) controller enclosing the directive), and I have a function my_function, attached to the controller's scope. I wonder if in the custom directive's link function if I can use scope.$watch to observe when my_function executes?

Here's a code for illustration:

<div ng-controller="MyCtrl">

    <my-directive></my-directive>

</div>

the controller:

app.controller('MyCtrl', function($scope) {

    $scope.my_function = function() {
    ...
    }

});

the custom directive:

app.directive('myDirective', function() {
    return {
        restrict: 'E',
        [scope: false,]
        ...
        link: function(scope, element, attrs) {

            // can I scope.$watch my_function here to check when it executes?

        }
    }
});

Update:

Here's my reason for asking this: When my_function (which essentially is a retrieve function through $http.get) executes, it should update an object, say my_data. If I try to scope.$watch my_data, there may be a situation where my_function executes and there is no change in my_data (such as when I edit an entry in my_data and decides to cancel the update anyway), thus a portion of the code that I want to execute in link function is not executed. So I want to make sure my code in link function executes whenever my_function executes, whether or not there is a change my_data.

Upvotes: 3

Views: 634

Answers (2)

gustavohenke
gustavohenke

Reputation: 41440

Here are two ways to solve your problem that I could think of.

1. Use a counter

You can always increment a counter when invoking my_function:

// This will reside in your controller
$scope.counter = 0;
$scope.my_function = function () {
  // do your logic
  $scope.counter++;
};

// This will reside in your directive
$scope.$watch( "counter", function () {
  // do something
});

2. Simply watch my_data

Assuming my_function will always override the my_data variable, you can use the default Angular behavior for $watch. You don't have to care if your backend has news for you or not, the reference will never be the same.

// in your controller
$scope.my_function = function () {
  $http.get(...).then(function ( response ) {
    $scope.my_data = response.data;
  });
};

// in your directive
$scope.$watch( "my_data", function () {
  // do something
});

Obviously, this is the cleaner way to do this, but you may get in trouble if you don't unit test because of one of the following:

  • You add any sort of logic around my_data that may conflict with your watcher;
  • You want to cache your HTTP calls.

I hope I was able to help you! Good luck.

Upvotes: 2

Hylianpuffball
Hylianpuffball

Reputation: 1561

Depending on what you're trying to do, you may not need $watch at all.

If the function isn't ever going to change, you can just make a dummy wrapper.

link: function(scope, element, attrs) {

        var oldFunc = scope.my_function;
        scope.my_function = function(sameArgs){
            //method_was_called();
            if(oldFunc){oldFunc(sameArgs);}
        }

    }

Then you can do whatever logic you want inside your wrapper function, either before or after you run the 'super' method.

Check also Javascript: Extend a Function

Upvotes: 1

Related Questions