W3docs

Bind value between Service and Controller/Directive

To bind values set an interval inside controller/directive, and you you will have a variable inside your scope, which holds the data from server. Another way is to use AngularJS events. See how you can do it.

Many AngularJS developers know about AngularJS services, controllers, and directives. As you know, AngularJS services are used to share global actions or variables. In general, services are used for global actions, though AngularJS already has the Value feature.

Warning

Since AngularJS is now a deprecated framework, you can use JavaScript modern frameworks like Vuejs, React and Angular, instead.

Now let's talk a little about the configuration and architecture of services and controllers. Imagine you have a service that represents a person. It has all getters and setters methods. We also have a data manager service that fetches data from anywhere every minute. We have several controllers and directives, and we want to bind this data inside them. Just a simple example: three controllers and two directives. Some need to bind data and must use our services. Remember we have a service called Person and a service called DataManager.

What can we do to solve our problem? Let's see what we have got.

AngularJs Service1

angular.module("myModule").service("Person", function () {
  var name = "Default";
  var listCount = 0;

  this.getName = function () {
    return name;
  };
  this.setName = function (Name) {
    name = Name;
  };

  this.getListCount = function () {
    return listCount;
  };
  this.setListCount = function (ListCount) {
    listCount = ListCount;
  };
});

AngularJs Service2

angular.module("myModule").service("DataManager", function ($interval, $http, Person) {
  $interval(function () {
    $http.get('[url]').then(function (data) {
      Person.setName(data.name);
      Person.setListCount(data.count);
    }); // getting the data every 1 minute
  }, 60000);
});

The following services provide data inside any controller or directive. Now let's see how we can bind that data, for example, inside the controller. Here is our controller.

AngularJs Controller

angular.module("myModule").controller("MyController", function ($scope, Person) {
  $scope.user = null;
  // here we need live data for person
});

As you see, displaying the data requires syncing the service with the scope. While AngularJS provides $watch or direct object reference binding, we can also use polling or events to keep the view updated. But how to do that? How to have live data inside our controller?

Here are the solutions for that problem.

Solution 1

This solution works well if you only need live data in one controller or directive. The approach is: set an interval inside the controller/directive so that a scope variable holds the data from the server. You can print that value in the view, and AngularJS will automatically update it. You can even set listeners on it. It is very simple, and you do not need the DataManager service. Here is an example:

AngularJs Controller Solution1

angular.module("myModule").controller("MyController", function ($scope, Person, $interval, $http) {
  $scope.user = {};
  $interval(function () {
    $http.get('[url]').then(function (data) {
      $scope.user.name = data.name;
      $scope.user.count = data.count;
    }); // getting the data every 1 minute
  }, 60000);
});

Maybe you think, why do we need the Person service? In general, you are right, but we can still use it in the controller to update the Person service data for other components.

Solution 2

The second solution works better if many components need to use the service (have live data). The approach is: AngularJS Events.

We can set a listener on any event. When the service fetches new data from the server, it sends a signal to notify components. We can use that event wherever needed. Let's see how to implement it.

AngularJs Service (Solution 2)

angular.module("myModule").service("DataManager", function ($interval, $http, Person, $rootScope) {
  $interval(function () {
    $http.get('[url]').then(function (data) {
      Person.setName(data.name);
      Person.setListCount(data.count);

      // here we have to send signal that we have a new live data from the server
      // we use Root Scope, because we don't know what scope architecture do we have
      $rootScope.$broadcast("newPersonData");
    }); // getting the data every 1 minute
  }, 60000);
});

AngularJs Controller (Solution 2)

angular.module("myModule").controller("MyController", function ($scope, Person) {
  $scope.user = {};

  $scope.$on('newPersonData', function () {
    $scope.user = {
      name: Person.getName(),
      count: Person.getListCount()
    };
  });
});

As you can see, we can use this event wherever needed. We set a listener on the event, and when the service has new data, we call the Person service methods to update the scope. You can also pass the data directly in the event payload. Note that while $rootScope.$broadcast is a common pattern, modern AngularJS applications often prefer $emit or service-based $watch for better performance and maintainability.