James-Jesse Drinkard
James-Jesse Drinkard

Reputation: 15703

How to pass a value from an AngularJS directive to a function in parent controller

I'm using Anguljarjs 1.4x. I'm trying to pass a value from an external function back to a directive. I've done some similar things before, but for some reason the function parameter is not coming back to my controller.

Here is some working plunker code I had to pass an external function to a directive. What I want to do now is add in a single text parameter value.

index.html

<!DOCTYPE html>
<html>

  <head>
    <script data-require="[email protected]" data-semver="1.4.2" src="https://code.angularjs.org/1.4.2/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <div id="app" ng-app="app">
    <div ng-controller="mainCtrl">
          <my-directive ctrl-fn="ctrlFn()"></my-directive> 
        </div>
      </div>

  </body>

</html>

myPage.html

<div>
  <button ng-click='ctrlFn()'>Click Here</button>
</div>

script.js

var app = angular.module('app', []);
app.controller('mainCtrl', function($scope){
  $scope.count = 0;
  $scope.ctrlFn = function() {
      console.log('In mainCtrl ctrlFn!');
      $scope.count += 10;
      console.log("count is: " + JSON.stringify($scope.count));
  };  
});

app.directive('myDirective', function() {
  return {
    restrict: 'E',
    scope: {
      'ctrlFn' : '&'
    },
   // template: "<div><button ng-click='ctrlFn()'>Click Here</button></div>",
   templateUrl: "./myPage.html",
    link: function(scope, element, attributes) {
      scope.ctrlFn();
      console.log("In link!");
    }
  };
});

When the app runs I get this: In mainCtrl ctrlFn!

count is: 10

In link!

After I click the button I get this: In mainCtrl ctrlFn!

count is: 20

As I said this all worked, until I added in a parameter. All I'm trying to do is add in a text param, but I'm getting an error when I tried this in myPage.html:

Error: cannot use 'in' operator to search for 'ctrlFn' in 'hello'

 <button ng-click='ctrlFn('hello')'>Click Here</button>

I added in a text value to my ng-click function and then created a param in the other places I have that function listed.

Any ideas as to how to do this?

Upvotes: 1

Views: 569

Answers (2)

georgeawg
georgeawg

Reputation: 48968

In the directive template use:

template: `
    <button ng-click="ctrlFn({$event: 'hello'})">
       Click Here
    </button>
`,

Use the directive as so:

<my-directive ctrl-fn="ctrlFn($event)"></my-directive> 

The DEMO on PLNKR

var app = angular.module('app', []);
app.controller('mainCtrl', function($scope){
  $scope.count = 0;
  $scope.ctrlFn = function(value) {
      $scope.count += 10;
      $scope.message = value;
  };  
});

app.directive('myDirective', function() {
  return {
    restrict: 'E',
    scope: {
      'ctrlFn' : '&'
    },
   template: `
      <div>
        <button ng-click="ctrlFn({$event:'hello'})">
          Click Here
        </button>
      </div>
    `,
    link: function(scope, element, attributes) {
      scope.ctrlFn();
    }
  };
});
<script src="//unpkg.com/[email protected]/angular.js"></script>
<body ng-app="app" ng-controller="mainCtrl">
      <my-directive ctrl-fn="ctrlFn($event)"></my-directive> 
      message={{message}}<br>
      count={{count}}
</body>


With expression ("&") binding, define the attribute:

<my-directive my-func="parentFn($event)">
</my-directive>

Invoke the function with the $event parameter defined as a local:

export default function myDirective() {
'ngInject';
    return {
        restrict: 'A',
        scope: {
            'myFunc': '&'
        },
        templateUrl: "./myPage.html",
        controller: myCtrl
    };

    function myCtrl($scope) {
        'ngInject';
        console.log("In myCtrl!");
        var answer = $scope.myFunc({$event: "Hello"});
        console.log(answer);
    }
}

Upvotes: 1

Daniel
Daniel

Reputation: 1420

Here is a working plunker of your code.

https://next.plnkr.co/edit/TWQEUUWq6h55uOIXDbuR

Basically, you need to remove the parenthesis from the directive

<my-directive ctrl-fn="ctrlFn"></my-directive>   

Then unwrap the function (in the directive) before you call it.

scope.ctrlFn = scope.ctrlFn();

This answer provides more information about unwrapping the function.

https://stackoverflow.com/a/27300517/1896352

Upvotes: 1

Related Questions