How to share data between multiple directives

Loading

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 the data object. The getData() method allows you to access the data, and the setData() 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 in directiveTwo, the message in directiveOne 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 the message attribute to the sharedMessage variable in the parent scope.
  • Directive Two: Also uses two-way binding to share the same message. When you click the button, the sharedMessage is updated, and the change is reflected in directiveOne 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 the message property.
  • Directive Two: Emits the 'messageChanged' event using $rootScope.$emit() when the button is clicked.
  • Data Flow: directiveOne listens for the event emitted by directiveTwo. When directiveTwo 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.

Leave a Reply

Your email address will not be published. Required fields are marked *