0

I am building a shadow copy directive to allow me to easily discard changes made to an object, and only commit them when a button is pressed. This is working fine but I'm finding that there are certain instances where I want to call a function inside the controller when the data is committed. How do I access a function in the controller from the directive by passing the function as an attribute?

HTML:

<div ng-app="myApp" ng-controller="myCtrl">
  <div my-directive="name" commit-function="saveData()">
    <input type="text" ng-model="name" />
    <button ng-click="commit()">
      Save
    </button>
  </div>
  <span>{{name}}</span>
  <br />
  <span>{{copiedName}}</span>
</div>

Directive:

myApp.directive('myDirective', function() {
  return {
    scope: true,
    link: function(scope, el, att) {
      scope[att.myDirective] = angular.copy(scope.$parent[att.myDirective]);
      scope.commit = function() {
        scope.$parent[att.myDirective] = angular.copy(scope[att.myDirective]);
      }
    }
  }
});

Controller:

myApp.controller('myCtrl', function($scope) {
  $scope.name = 'Frank';
  $scope.copiedName = 'Freddie';

  $scope.saveData = function() {
    $scope.copiedName = $scope.name;
  }
});

I set the commit-function attribute to saveData() and now I want to get the function from that attribute.

I know I can use an isolated scope and set commitFunction: '&' but as I understand it, I then cannot access the commit function of the directive.

Here is a codepen showing what I'm after. I would expect when this is working that saveData has been fired and the display for name and copiedName would match.

4
  • what do you mean by then cannot access the commit function? Commented Dec 8, 2015 at 20:57
  • If I use an isolated scope, the commit function does not fire when the button is pressed. I assumed this is because the controller does not know anything about the directive scope therefore does not know about the commit function. Commented Dec 8, 2015 at 21:03
  • Only the requirement is to. don't update ng-model value till button is pressed?? Commented Dec 8, 2015 at 21:10
  • It's the main requirement. I want to use a directive so I can reuse the functions. The actual directive has four or five functions in it. Commented Dec 8, 2015 at 21:32

1 Answer 1

2

To be able to invoke a method specified in the attribute commit-function, you can use $apply, since the $rootScope is already in progress, you can add $timeout

myApp.directive('myDirective',['$timeout', function($timeout) {
  return {
    scope: true,
    link: function(scope, el, att) {
      scope[att.myDirective] = angular.copy(scope.$parent[att.myDirective]);
      scope.commit = function() {
        scope.$parent[att.myDirective] = angular.copy(scope[att.myDirective]);
        $timeout(function(){
           scope.$apply(att.commitFunction);
        },0);}
    }
  }
}]);
Sign up to request clarification or add additional context in comments.

1 Comment

This works with a couple of modifications: 1) commit-function="saveData", 2) scope.$apply(scope.$parent[att.commitFunction]);. Pen: codepen.io/anon/pen/zrxede

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.