Exchange Data Between Directive and Controller in AngularJS



AngularJS is an amazing JavaScript library and an excellent framework for any modern web application of any scale.
As with any large and complex framework such as AngularJS, a lot is possible.

Today I will demonstrate one of the problems I had to work around on a project for a client. The solution, however, is amazingly simple and elegant.

The project required me to write a directive for a canvas, get the Base64 image data when a user draws on it, and make it available to the controller of the page which contains the directive.
To do this I had to find out how to exchange data between a Directive and Controller in AngularJS.

This boils down to the fact that you need to access the scope of a Directive from a page Controller and access the scope of a page Controller from a Directive.

These scopes are isolated from each other. So in order to do this we need to emulate the ng-model behavior of an input in our Directive.

Let’s take a simple example and make a directive that has a counter which goes up by one every second.

var app = angular.module('myApp', [])

app.directive('counter',
  function($timeout) {
    return {
      restrict: 'EAC',
      template: `<div>Directive Counter: {{internalCount}}</div>`,
      link: function($scope, element) {
        $scope.internalCount = 0;
        function addCount() {
          $timeout(function() {
            $scope.internalCount += 1;

            addCount();
          }, 1000)

        }
        addCount();

      }
    };
  }
)

By default, this scope will be isolated from the scope of the page that contains the directive.

Now let’s say we have the following controller:

app.controller('myCtrl', function($scope) {
    $scope.count = 0;
});

And the following template:



<div ng-app="myApp">
    <div ng-controller="myCtrl">
        <counter></counter>
        {{count}}
    </div>
</div>

The problem: we would like to bind the count variable of myCtrl to the internalCount variable of the counter directive.
This can easily be solved by binding a variable from the controller to the scope of the directive. To do this we will pass the variable as an attribute to the directive and use it to initialize the scope of the directive

This is done by adding the ‘scope‘ parameter to the directive and picking a name for the attribute. Here it is model, so we will initialize internalCount with ‘=model’

Binding the data

scope: {
    internalCount: '=model'
}

We can also remove the initialization of the internalCount variable in the directive.

Your directive should now look like this:

app.directive('counter',
  function($timeout) {
    return {
      restrict: 'EAC',
      template: `<div>Directive Counter: {{internalCount}}</div>`,
      scope: {
        internalCount: '=model'
      },
      link: function($scope, element) {
        function addCount() {
          $timeout(function() {
            $scope.internalCount += 1;

            addCount();
          }, 1000)

        }
        addCount();

      }
    };
  }
)

And your template like this:

<div ng-app="myApp">
    <div ng-controller="myCtrl">
        <counter model="count"></counter>
        {{count}}
    </div>
</div>

You will find a working fiddle here with all the code to this quick tutorial on how to exchange data between a directive and controller in AngularJS.

Share the knowledge!
Share on Facebook0Tweet about this on Twitter0Share on Google+0Share on StumbleUpon1Share on Reddit2Share on LinkedIn19Share on TumblrBuffer this pageDigg this

Comments

You may also like...

Stay updated
Subscribe!