krsna
krsna

Reputation: 4353

How to expose a value from Service to the HTML in Angular JS

I have an AngularJS service where I wrote the logic of button's click functionality - Setting timeout for 3 seconds to display a pop up once the button is clicked.

$timeout is working fine as I see the output in the console. What I'm not able to do is exposing the timeoutFlag in the HTML template on the ng-if condition.

Could anyone please advise what I'm missing here. Appreciate the help!

Service

angular.module('myApp').service('appService', appService);
appService.$inject = ['$rootScope', '$timeout'];

function appService($rootScope, $timeout) {

  button = document.getElementById('clickmeBtn');
  button.addEventListener('click', function() {

    $rootScope.timeoutFlag = true;
    console.log('service before timeout - ' + $rootScope.timeoutFlag);
    $timeout(function() {
      $rootScope.timeoutFlag = false;
      console.log('service after timeout - ' + $rootScope.timeoutFlag)
    }, 3000)
  });
}

Controller

(function() {
  angular.module('myApp', []).controller('appController', appController);
  appController.$inject = ['$scope', '$rootScope', 'appService'];

  function appController($scope, $rootScope, appService) {
    var vm = this;
  }
})();

HTML

<!doctype html>
<html ng-app="myApp">

<body ng-controller="appController as vm">

  <p ng-if="$rootScope.timeoutFlag">Button Clicked</p>

  <button id="clickmeBtn">Click me!</button>

  <script src="node_modules/angular/angular.min.js"></script>
  <script src="scripts/app.controller.js"></script>
  <script src="scripts/app.service.js"></script>
</body>

</html>

Upvotes: 1

Views: 93

Answers (1)

georgeawg
georgeawg

Reputation: 48968

Because the click event comes from outside the AngularJS execution context, the modification of scope needs to be brought into the AngularJS execution context with the $apply method:

angular.module('myApp').service('appService', appService);
appService.$inject = ['$rootScope', '$timeout'];

function appService($rootScope, $timeout) {

  button = document.getElementById('clickmeBtn');
  button.addEventListener('click', function() {

    $rootScope.$apply(function() {
       $rootScope.timeoutFlag = true;
    });
    console.log('service before timeout - ' + $rootScope.timeoutFlag);
    $timeout(function() {
      $rootScope.timeoutFlag = false;
      console.log('service after timeout - ' + $rootScope.timeoutFlag)
    }, 3000)
  });
}

Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc...

For more information, see AngularJS Developer Guide - Integration with the browser event loop


I'm still not able to display the pop up based on the $rootScope.timeoutFlag value in ng-if condition.

Remove the reference to $rootscope in the HTML:

<body ng-controller="appController as vm">

  <p ng-if=" ̶$̶r̶o̶o̶t̶S̶c̶o̶p̶e̶.̶ timeoutFlag">Button Clicked</p>

  <button id="clickmeBtn">Click me!</button>

The scope of the controller inherits properties from $rootScope.

The DEMO on PLNKR

Upvotes: 2

Related Questions