21

I have some data called foo which lives in a scope which is parent to three children:

<div ng-init="foo=[1, 2, 3]">
    <bar foo="{{foo}}" baz="{{odp}}" />
    <mpq foo="{{foo}}" bats="{{maktz}}" />
    <ktr foo="{{foo}}" otr="{{ompg}}" />
</div>

bar.scope = {foo: '=', baz: '@'};
mpq.scope = {foo: '=', bats: '@'};
ktr.scope = {foo: '=', otr: '@'};

What is the best way to share foo between those three directives? Options include:

  • Use an isolated scope to pass in foo three times, thereby duplicating it across four scopes
  • Have the child directives inherit the parent scope, and find baz, bats, or otr on attrs
  • Put foo on the $rootScope and inject that into the child directives

Or is there another approach that is better?

Nick Heiner
  • 119,074
  • 188
  • 476
  • 699

1 Answers1

28

You can create a factory that you can pass to each directive or controller. That will make sure you only have one instance of the array at any given time. EDIT: The only gotcha here is to make sure you're setting reference types and not primitive types on your directive scopes, or you'll end up duplicating the values in each scope.

Here is an example on Plnkr.co

app.controller('MainCtrl', function($scope, dataService) {
  $scope.name = 'World';
  //set up the items.
  angular.copy([ { name: 'test'} , { name: 'foo' } ], dataService.items);
});

app.directive('dir1', function(dataService){
  return {
    restrict: 'E',
    template: '<h3>Directive 1</h3>' + 
    '<div ng-repeat="item in data.items">' + 
      '<input type="text" ng-model="item.name"/>' + 
    '</div>',
    link: function(scope, elem, attr) {
      scope.data = dataService;
    }
  };
});

app.directive('dir2', function(dataService){
  return {
    restrict: 'E',
    template: '<h3>Directive 2</h3>' + 
    '<div ng-repeat="item in data.items">' + 
      '<input type="text" ng-model="item.name"/>' + 
    '</div>',
    link: function(scope, elem, attr) {
      scope.data = dataService;
    }
  };
});

app.directive('dir3', function(dataService){
  return {
    restrict: 'E',
    template: '<h3>Directive 3</h3>' + 
    '<div ng-repeat="item in data.items">' + 
      '<input type="text" ng-model="item.name"/>' + 
    '</div>',
    link: function(scope, elem, attr) {
      scope.data = dataService;
    }
  };
});

app.factory('dataService', [function(){
  return { items: [] };
}]);

HTML

  <dir1></dir1>
  <dir2></dir2>
  <dir3></dir3>
A J A Y
  • 585
  • 1
  • 7
  • 22
Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
  • 2
    I considered this, but the angular docs discourage it: http://docs.angularjs.org/misc/faq – Nick Heiner Nov 26 '12 at 22:13
  • 4
    I presume you're talking about this: "Conversely, don't create a service whose only purpose in life is to store and return bits of data." It really depends on what you're doing with the data. If you're manipulating it at all in a uniform way across controllers/directives/etc (which most people would be), then create a service... otherwise, just stick it in $rootScope. As long as whatever you're doing is easy to follow and, most importantly, doesn't break testability, it's kosher. – Ben Lesh Nov 26 '12 at 23:46
  • ... as @pkowslowski.opensource said above: It really depends on the nature of your data. – Ben Lesh Nov 26 '12 at 23:49
  • 1
    I can't believe I forgot you can hold it in a service #facepalm. – Michael J. Calkins Dec 16 '13 at 16:08
  • 1
    Is it realy good way to use services to pass variables? Isnt it antipatern? And actualy if you will change service variable thru function, by ng-click for example, you need to use $scope.$apply to make changes life in other controllers. I don't think services were made to pass variables, but I'm not sure? – Pikachu Sep 29 '14 at 16:34