Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can multiple directives for one element share an isolated scope?

Two directives on the same element can not both have isolated scope, but can they both use the same scope isolated from their parent? And can they both use properties bound to the isolated scope?

For example, if I have two directives on an element

<e-directive a-directive prop="parentProp"/>

And one directive defines an isolated scope with a bound property

App.directive('eDirective', function() {
  return {
    restrict: 'E',
    scope: {
      localProp: '=prop'
    },
    ...
  };
});

Does the other directive get that scope and can it use the bound property?

App.directive('aDirective', function() {
  return {
    restrict: 'A',
    link: function postLink(scope, element, attrs) {
        scope.$watch('localProp', function(newProp, oldProp) {
          ...
        }
    },
    ...
  };
});

My initial attempt (pretty much coded as above) failed.

like image 352
Robert Antonucci Avatar asked Apr 22 '14 13:04

Robert Antonucci


People also ask

Can we use multiple directives in angular?

You can not use two structural directives on the same element. You need to wrap your element in another one. It's advised to use ng-container since it wont be rendered in DOM.

How is scope in directive different from scope in controller?

By default, directives do not create their own scope; instead they use the scope of their parent, generally a controller (within the scope of which the directive is defined). We can change the default scope of the directive using the scope field of the DDO (Data Definition Object).

What is shared scope in Angularjs?

Shared scope: directive and controllers share the scope and the data. We cannot pass data explicitly to the directive. 2. Inherited scope: directive inherits the scope of the controller.


2 Answers

I suggest you make use of communicating between the directives' controllers via the require property of the secondary directive. The first directive (e-directive) holds the isolated scope, while the second helper directive (a-directive) has a reference to the first directive and sets properties via functions defined on the first directive. A small sample would be (see plunker):

<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" data-semver="1.2.16"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <div e-directive config="parentConfig" a-directive></div>
  </body>

</html>

and the javascript:

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

app.controller('MainCtrl', function($scope) {
  $scope.parentConfig = {};
});

app.controller('ECtrl', function ( $scope ) {
  this.setProp = function(newProp){$scope.config.prop = newProp;};

  $scope.$watch('config', function(newProp, oldProp) {
    console.log(oldProp, newProp);
  });
});

app.directive('eDirective', function() {
  return {
    restrict: 'A',
    scope: {
      config: '='
    },
    controller: 'ECtrl',
    link: function(scope, element, attrs) {
      scope.config.prop ="abc";
    }
  };
});

app.directive('aDirective', function() {
  return {
    restrict: 'A',
    require: 'eDirective',
    link: function(scope, element, attrs,ctrl) {
        ctrl.setProp("def");
    }

  };
});
like image 179
zszep Avatar answered Nov 13 '22 15:11

zszep


Instead of an isolate scope, the directives can create a new child scope, which will be shared by both directives. If you need to modify parentProp in a directive, inject and use $parse:

<div ng-controller="MyCtrl">
  <e-directive a-directive prop="parentProp"></e-directive>
</div>

Javascript:

var app = angular.module('myApp', []);
app.controller('MyCtrl', function($scope) {
    $scope.parentProp = { prop1: 'value1' };
});
app.directive('eDirective', function($parse) {
  return {
    restrict: 'E',
    scope: true,
    template: '<div>dir template: {{eDirLocalProp}}<br>'
          + '<a href ng-click="eDirChange()">change</a></div>',
    link: function(scope, element, attrs) {
      scope.eDirProp1     = 'dirPropValue';
      var model           = $parse(attrs.prop);
      scope.eDirLocalProp = model(scope);
      scope.eDirChange    = function() {
          scope.eDirLocalProp.prop1 = "new value";
      };
    }
  };
});
app.directive('aDirective', function() {
  return {
    scope: true,
    link: function postLink(scope, element, attrs) {
      scope.$watchCollection(attrs.prop, function(newValue) {
        console.log('aDirective', newValue);
      });
    },
  };
});

fiddle

If both directives need to create properties on the new child scope, use some kind of naming convention to prevent name clashes. E.g., scope.eDirProp1 = ... and scope.aDirProp1 = ....

like image 37
Mark Rajcok Avatar answered Nov 13 '22 15:11

Mark Rajcok