Shivkumar
Shivkumar

Reputation: 1903

How do I share scope between two directives in AngularJS?

I want to share the $scope between the following two directives:

One23SRCApp.directive('directive1',function() {
    return {
        restrict: "A",
        scope:true,
        link: function (scope, element, attrs) {
           scope.tablename = "table";
        }
    };
});


One23SRCApp.directive('directive2',function() {
    return {
        restrict: "A",
           link: function (scope, element, attrs) {
           var tablename = scope.tablename;
        }
    };
})

In the HTML, I have:

<input type="text" directive2 placeholder="Search Models..."> 

<table directive1>
  <tr>
     <td>column1</td>
     <td>column1</td>
   </tr>
</table>

I have created the directive named "directive1" with isolated scope, assigning the name "table" to the scope.tablename property. I am not able access this scope property in the other directive.

So how can I access the scope of one directive in another?

Upvotes: 17

Views: 33874

Answers (4)

Steve Kl&#246;sters
Steve Kl&#246;sters

Reputation: 9457

AngularJS supports directive controllers, which are controllers that are shared between multiple directives that require the same controller. This allows you to access and modify tableConfig in any directive that requires that controller, without having to declare a separate service or event. For more information, look at "Creating Directives that Communicate" in the directives documentation.

This is how ngModel and ngForm work, for example.

Upvotes: 21

Joris Brauns
Joris Brauns

Reputation: 363

The sample of Chandermani is working. However this way you still have to assign the attribute on your directive and its not isolated anymore. This is a pollution on the scope...

My advice is to share your isolated scope by using the controller an passing it this way. Your house, your code! Think before you code but most of all... ENJOY!

One23SRCApp.directive('directive1',function() {
    return {
         restrict: "A",
         scope: true,
         controller : function($scope){
              $scope.tableconfig= {};
              this.config = function (){ 
                   return $scope.tableconfig;
              }
         },
         link: function (scope, element, attrs) {
             scope.tableconfig.tablename= "table";
         }
    }
});


One23SRCApp.directive('directive2',function() {
     return {
           restrict: "A",
           //^ -- Look for the controller on parent elements, not just on the local scope
           //? -- Don't raise an error if the controller isn't found
           require: "^directive1",
           link: function (scope, element, attrs) {
               var tablename = scope.config().tablename;
           }
    }
});

Usage

<!-- Notice, no need to share a scope as attribute -->
<div directive1>
    <div directive2>
    </div>
</div>

Upvotes: 4

Erik Honn
Erik Honn

Reputation: 7576

My suggestion would be to use a shared resource, e.g. a service. Services are singletons, meaning there is only ever one instance of each service, so you can use them to share data between directives, controllers, scopes and even when changing page through routing.

You would define the resource service like this:

app.factory("MyResource",function(){
    return {};
});

You could then inject that service into your directives (and controllers if need be) and use it like this.

One23SRCApp.directive('directive1', ['MyResource', function(MyResource) {
    return {
        restrict: "A",
        scope:true,
        link: function (scope, element, attrs) {
           var resource = MyResource;
           resource.name = 'Foo';
        }
    };
});
One23SRCApp.directive('directive2', ['MyResource', function(MyResource) {
    return {
        restrict: "A",
        link: function (scope, element, attrs) {
           var resource = MyResource;
           console.log(resource.name);
        }
    };
});

Directive2 will log 'Foo' since the resource is shared. Although make sure your directives are run in the correct order!

**

You could also do a two way data-binding from each directive into the parent scope (see Chandermani answer for that), but the above is a very useful and powerful way to get data where you need it without having to broadcast or keep track of exactly where things are in the html.

Edit: While the above is very useful when sharing info between controllers and routes, check out stevuu answer. It seems better for directives (although I have not tried it).

Upvotes: 16

Chandermani
Chandermani

Reputation: 42669

You can do a $rootScope.$broadcast on items that you need to sync across directive.

Or you can pass a object to your directive1 isolated scope, which would act as a communication mechanism. On this object if you change sub property like tablename, that would affect in the parent scope.

Something like

One23SRCApp.directive('directive1',function() {
    return {
        restrict: "A",
        scope:{tableconfig:'='},
        link: function (scope, element, attrs) {
           scope.tableconfig.tablename= "table";
        }
    };
});


One23SRCApp.directive('directive2',function() {
    return {
        restrict: "A",
           link: function (scope, element, attrs) {
           var tablename = scope.tableconfig.tablename;
        }
    };
})

The HTML becomes

<table directive1 tableconfig='tableconfig'>
  <tr>
     <td>column1</td>
   <td>column1</td>
   </tr>
</table>

Your controller should have this object defined

$scope.tableconfig={};

Upvotes: 5

Related Questions