2
votes

What is the preferred way to link/bind two directives together? I have a controller with two directives, first directive is a select element, after selecting option, second directive should process selected item value.

App code:

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

app.controller('MainCtrl', function() {
  var sharedData = { selectedId: '' };

  var vm = this;

  vm.sharedData = sharedData;
});

app.directive('directiveA', ['$compile', function($compile) {
  return {
    restrict: 'E',
    scope: {
      selectedId: '='
    },
    template: '<select data-ng-model="vm.sharedData.selectedId" data-ng-options="currentSelect.Id as currentSelect.Name for currentSelect in vm.sharedData.availableSelects track by currentSelect.Id"><option value="">Select option</option></select><p>Directive A, selected ID: {{vm.sharedData.selectedId}}</p>',
    bindToController: true,
    controllerAs: 'vm',
    controller: function() {
      vm = this;

      vm.sharedData = {
        availableSelects: [
          {Id:1, Name: 'Option 1'},
          {Id:2, Name: 'Option 2'},
          {Id:3, Name: 'Option 3'},
          {Id:4, Name: 'Option 4'}
        ]
      }
      vm.logMessage = logMessage;

      function logMessage(selectedId) {
        console.log('directiveA: ' + selectedId);
      }
    },
    link: function($scope, elem, attr, ctrl) {
      attr.$observe('selectedId', function(selectedId) {
        ctrl.logMessage(selectedId);
      });
    }
  };
}]);

app.directive('directiveB', ['$compile', function($compile) {
  return {
    restrict: 'E',
    scope: {
      selectedId: '='
    },
    template: '<p>Directive B, selected ID: {{vm.sharedData.selectedId}}</p>',
    bindToController: true,
    controllerAs: 'vm',
    controller: function() {
      vm = this;

      vm.logMessage = logMessage;

      function logMessage(selectedId) {
        console.log('directiveB: ' + selectedId);
      }
    },
    link: function($scope, elem, attr, ctrl) {
      attr.$observe('selectedId', function(selectedId) {
        ctrl.logMessage(selectedId);
      });
    }
  };
}]);

HTML code:

<!DOCTYPE html>
<html data-ng-app="plunker" data-ng-strict-di>
  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link href="style.css" rel="stylesheet" />
    <script data-semver="1.4.1" src="https://code.angularjs.org/1.4.1/angular.js" data-require="[email protected]"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl as vm">
    <p>MainCtrl, selected ID: {{vm.sharedData.selectedId}}</p>
    <directive-a data-selected-id="vm.sharedData.selectedId"></directive-a>
    <directive-b data-selected-id="vm.sharedData.selectedId"></directive-b>
  </body>

</html>

Here is a Plunker example:

http://plnkr.co/edit/KVMGb8uAjUwD9eOsv72z?p=preview

What I'm doing wrong?

Best Regards,

1
You have two directives which require isolated scope on the same element which is not allowed. This a duplicate question. stackoverflow.com/questions/20470662/… - Ernesto Rendon
IF i understood your requirement correctly , think u need to can use require for the refernces between two controllers, stackoverflow.com/questions/30673459/… - Shushanth Pallegar
Hmm, the stackoverflow.com/questions/20470662/… is about having two directives on the same element (<input>), but here I have two independent directives on same variable. - Sassa
I would like to avoid using require parameter - this two directives should be independent. - Sassa

1 Answers

1
votes

The key issue revolves around your use of isolated scopes:

scope: {
  selectedId: '='
},

With controllerAs binding:

controllerAs: 'vm',

What this essentially does, to put it basically, is it places the view model onto the directives scope, accessed through the alias you assign in the controllerAs. So basically in your html when you go:

<directive-a data-selected-id="vm.sharedData.selectedId"></directive-a>

You are actually accessing the directive-a view model, NOT the MainCtrl view model. BECAUSE you set directive-a as having an isolate scope... which is a new scope, isolated from the MainCtrl.

What you need to do is more along the following lines:

http://plnkr.co/edit/wU709MPdqn5m2fF8gX23?p=preview


EDIT

TLDR: I would recommend having unique view model aliases (controllerAs) when working with isolated scopes to properly reflect the fact that they are not the same view model.