In AngularJS, there are multiple ways to share data between multiple directives. Since each directive can have its own isolated scope, sharing data between them requires a strategy that bridges the communication. Below are various techniques you can use to share data between directives:
1. Using a Shared Service
One of the most common and recommended ways to share data between directives is by using a shared service. AngularJS services are singleton objects that can be injected into different parts of your application, including multiple directives, to share data or behavior.
How it works:
- You create a service that holds the shared data or logic.
- You inject the service into the directives that need to access or modify the shared data.
- Since services are singletons, all directives that inject the same service will share the same instance of the service, making data sharing easy.
Example:
Step 1: Define a Service
angular.module('app', [])
.service('SharedDataService', function() {
var data = { message: "Hello from shared service!" };
return {
getData: function() {
return data;
},
setData: function(newData) {
data.message = newData;
}
};
});
Step 2: Define Directives Using the Service
angular.module('app')
.directive('directiveOne', function(SharedDataService) {
return {
restrict: 'E',
template: '<div>{{ message }}</div>',
link: function(scope) {
scope.message = SharedDataService.getData().message;
}
};
})
.directive('directiveTwo', function(SharedDataService) {
return {
restrict: 'E',
template: '<button ng-click="changeMessage()">Change Message</button>',
link: function(scope) {
scope.changeMessage = function() {
SharedDataService.setData("Message changed from Directive Two!");
};
}
};
});
Step 3: Usage in HTML
<div ng-app="app">
<directive-one></directive-one>
<directive-two></directive-two>
</div>
Explanation:
- Service (
SharedDataService
): This service stores thedata
object. ThegetData()
method allows you to access the data, and thesetData()
method allows you to update it. - Directive One: This directive fetches the message from the
SharedDataService
and displays it. - Directive Two: This directive allows you to update the message in the
SharedDataService
. - Data Flow: Since both directives inject the same
SharedDataService
, they share the same data instance. When you click the button indirectiveTwo
, the message indirectiveOne
is automatically updated because they both rely on the same service.
2. Using Parent-Child Scope Communication
Another method to share data is through parent-child scope communication. In this case, you can pass data from a parent controller to multiple child directives via scope inheritance or by using scope
bindings in the directives.
How it works:
- The parent controller can define a scope variable and pass it down to its child directives through
@
,=
, or&
bindings. - The child directives can update this data, and since they share the parent scope, the changes will be reflected in all child directives.
Example:
Step 1: Define a Parent Controller and Directives
angular.module('app', [])
.controller('ParentController', function($scope) {
$scope.sharedMessage = "Hello from Parent!";
})
.directive('directiveOne', function() {
return {
restrict: 'E',
scope: {
message: '='
},
template: '<div>{{ message }}</div>'
};
})
.directive('directiveTwo', function() {
return {
restrict: 'E',
scope: {
message: '='
},
template: '<button ng-click="message = \'Message changed by Directive Two!\'">Change Message</button>'
};
});
Step 2: Usage in HTML
<div ng-app="app" ng-controller="ParentController">
<directive-one message="sharedMessage"></directive-one>
<directive-two message="sharedMessage"></directive-two>
</div>
Explanation:
- Parent Controller: Defines a
sharedMessage
variable in the$scope
. - Directive One: Uses two-way binding (
=
) to bind themessage
attribute to thesharedMessage
variable in the parent scope. - Directive Two: Also uses two-way binding to share the same
message
. When you click the button, thesharedMessage
is updated, and the change is reflected indirectiveOne
as well. - Data Flow: Since both directives share the same
sharedMessage
variable via two-way binding, changes in either directive will automatically update the message in both.
3. Using Events (Custom Events)
Another approach to share data between directives is using custom events. This allows directives to communicate by emitting events on the $rootScope
or the parent scope, and other directives can listen for these events.
How it works:
- One directive emits an event (with or without data).
- Other directives listen for that event and update their scope when the event is triggered.
Example:
Step 1: Define Directives Using Events
angular.module('app', [])
.directive('directiveOne', function($rootScope) {
return {
restrict: 'E',
template: '<div>{{ message }}</div>',
link: function(scope) {
scope.message = "Waiting for event...";
$rootScope.$on('messageChanged', function(event, data) {
scope.message = data;
});
}
};
})
.directive('directiveTwo', function($rootScope) {
return {
restrict: 'E',
template: '<button ng-click="changeMessage()">Change Message</button>',
link: function(scope) {
scope.changeMessage = function() {
$rootScope.$emit('messageChanged', 'Message updated via event!');
};
}
};
});
Step 2: Usage in HTML
<div ng-app="app">
<directive-one></directive-one>
<directive-two></directive-two>
</div>
Explanation:
- Directive One: Listens for the
'messageChanged'
event using$rootScope.$on()
. When the event is emitted, it updates themessage
property. - Directive Two: Emits the
'messageChanged'
event using$rootScope.$emit()
when the button is clicked. - Data Flow:
directiveOne
listens for the event emitted bydirectiveTwo
. WhendirectiveTwo
emits the event,directiveOne
updates the message.
4. Using require
to Access Parent Directive’s Data
You can also share data between directives by using the require
property in the directive definition. This allows a directive to require another directive, and it can access its scope or controller directly.
How it works:
- One directive can require another directive, and access its controller or scope properties.
- The required directive can expose data or methods for the parent directive to use.
Example:
angular.module('app', [])
.directive('parentDirective', function() {
return {
restrict: 'E',
controller: function($scope) {
$scope.parentMessage = "Message from Parent Directive!";
},
template: '<div>{{ parentMessage }}</div><child-directive></child-directive>'
};
})
.directive('childDirective', function() {
return {
restrict: 'E',
require: '^parentDirective', // Access parent directive's controller
link: function(scope, element, attrs, parentCtrl) {
scope.childMessage = parentCtrl.parentMessage;
},
template: '<div>{{ childMessage }}</div>'
};
});
Explanation:
- Parent Directive: Exposes
parentMessage
on its controller, which is available for child directives. - Child Directive: Uses
require: '^parentDirective'
to access the parent directive’s controller and share data with it.