1

We are using Angular 1.4.2 and I am trying to take a count value from a directive using ng-click, pass it to a function, then pass it up to the parent controller. After some effort it is working in a plunker, but unfortunately when I tried to move this functionality back into the main code, I'm not able to get a controller to bind to the isolated scope.

Should be simple, but I've tried injecting the current controller into the directive and trying to create a new controller, but nothing happens when I press click on the button.

Here is the code:

TEMPLATE:

<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@1.4.2" 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(count = count + 10)"></my-directive> 
        </div>
      </div>
  </body>

</html>

SCRIPT:

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

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

Here is the template code I'm trying to modify in the main code base:

<div>
    <div layout="row">
        <results-loader ctrl-fn="ctrlFn(count = count + 10)"></results-loader>
        <md-button class="md-raised md-primary md-button" ng-click="ctrlFn()" flex>Click Me</md-button>
    </div>
</div>

and here is where I use an existing controller in my directive as a parent controller. It's defined in a route, rather than ng-controller and is already used for this view.

myresultsCtrl.$inject = ['$scope', ' myService'];
        /* @ngInject */
        function myresultsCtrl($scope, myService) {
            $scope.count = 0;
etc...

however, it apparently isn't bound properly as I never hit the directive or this function with ng-click.

Like I said I tried adding a new controller to the template, then I tried injecting an existing controller into the directive, but neither worked. I took out the template from the directive and tried to put the ng-click directly into the template with ctrl-fn, but I wasn't sure how to wire up the click with the call to the ctrl-fn attribute of the directive with both in the template? The idea here is to move the template into it's own html file and reference it from the directive, as in: template: "myFile.html. I'm trying to enscapsulate as much as possible to make this into a reusable component.

I haven't worked much with custom directives.

Here is the direct link to the plunker.

James Drinkard
  • 15,342
  • 16
  • 114
  • 137

2 Answers2

0

I don't know your exact assignment, but rethink your architecture. Why do you want to count the value in the directive? In your simple case it would be better to count the value in a service or in the controller, not a directive.

Injecting controller in the directive is anti-angular pattern. You need to rethink your intentions. It is better to pass the number to the directive, make your calculations there and send your number back to the controller. It would work without extra code, because of the two-way data binding. Here a fork of your plunker: http://plnkr.co/edit/KpB6bv5tHvXSvhErLcEp?p=preview Main part is the definiton of the directive: <div><span>{{count}}</span><br /><button ng-click='myFunction()'>Calculate</button></div>

Oktay Myumyunov
  • 120
  • 1
  • 16
  • I need the count each time the user clicks a button to return a set number of results. When it loads the page it shows 10 results, when they click it shows those 10 + 10 more, when the click again it shows 10 + 10 + 10 or 30. I'm calling a service to pull the results after I pass the value to the parent controller. – James Drinkard Feb 07 '17 at 15:42
0

I prefer not to answer my own questions as that can have a negative appearance, but in this case, I don't know if I could have explained the question well enough to get the right answer. What was throwing me off was integrating my working plunker code into our existing code base.

Where I got stuck was how to setup the controller properly for this use case. Though I declared my controller, in the module and injected the controller as it was already bound to that view, I needed to define the controller in the directive itself. Once I did all three together, everything started working.

Here are some code snippets:

angular.module('directiveName', [])
        .directive('directiveName', directiveName)
        .controller('injectedCtrl', injectedCtrl)
        etc...

var directive = {
        restrict: 'E',
        scope: {
            'ctrlFn' : '&'
        },
        template: "<div><button ng-click='ctrlFn()'>Click Here</button></div>",
        controller: "injectedCtrl",
        link: function(scope, element, attributes) {
            scope.ctrlFn(); //This will pass to the parent controller: injectedCtrl, where $scope resides.
        }
    }
    return directive;   
}


injectedCtrl.$inject = ['$scope', 'myService'];
    /* @ngInject */
    function injectedCtrl($scope, myService) {
    $scope.ctrlFn = function() {
        //do something
    }
    etc...

HTML CODE:

When the button is clicked from the directive, ctrlFn here is a reference that is under my directives isolated scope in the DDO. This takes the external function that was passed in, namely: ctrlFn() which can then be invoked from the directive to call the parent controller.

<div layout="row">
        <results-loader ctrlFn="ctrlFn()"></results-loader> 
    </div>

I'm posting this to help someone else that might have this use case as it was not easy to figure this out.

Dah Wahlins post goes into this subject in greater detail: Creating Custom AngularJS Directives Part 3 - Isolate Scope and Function Parameters and what helped to get my thinking straightened out.

James Drinkard
  • 15,342
  • 16
  • 114
  • 137