# AngularJS - Watch and Apply ## Lesson Objectives 1. Use $watch to listen for changes on variables 1. Use $apply to force a redraw of the page ## Use $watch to listen for changes on variables ### Use 1 We can create event listeners for any property of the $scope variable. This can be useful if you have a scope variable that changes frequently from multiple sources, but you want to perform the same action each time it updates. ```javascript $scope.$watch('somevar', function(newValue, oldValue){ //will run whenever $scope.somevar changes }); ``` ### Example 1 file: index.html ```html
{{somevar}}
``` file: js/app.js ```javascript const app = angular.module('MyApp', []); app.controller('MainController', ['$scope', function($scope){ $scope.somevar = 'foo'; $scope.$watch('somevar', function(newValue, oldValue){ //will run whenever $scope.somevar changes console.log(newValue, oldValue); }); this.changeScopeVar = function(){ $scope.somevar = 'bar'; }; }]); ``` ### Use 2 If no string is passed as first parameter. Entire scope is watched. This is useful for controller properties when controller alias is not known. **NOTE** that the two parameters for the old value and new value of $scope will appear identical, since they both point to the same object in memory. ```javascript $scope.$watch(function(newValue, oldValue){ //will run whenever $scope changes //NOTE: newValue and oldValue will have same property values, since both point the same object, which has been modified }); ``` ### Example 2 file: index.html ```html
{{somevar}}
``` file: js/app.js ```javascript const app = angular.module('MyApp', []); app.controller('MainController', ['$scope', function($scope){ $scope.somevar = 'foo'; $scope.$watch(function(newValue, oldValue){ //will run whenever $scope.somevar changes console.log(newValue, oldValue); }); this.changeScopeVar = function(){ $scope.somevar = 'bar'; }; }]); ``` ### Use 3 You can also watch any variables by passing in a function as the first param that returns the variable to be watched ```javascript $scope.$watch(function(){ return foo; }, function(newValue, oldValue){ //will fire when global foo variable is changed }); ``` ### Example 3 file: index.html ```html
``` file: js/app.js ```javascript const app = angular.module('MyApp', []); const someThirdPartyVariable = 'foo'; app.controller('MainController', ['$scope', function($scope){ $scope.$watch( function(){ return someThirdPartyVariable; }, function(newValue, oldValue){ //will fire when global foo variable is changed console.log(newValue, oldValue); } ); this.clickFunction = function(){ someThirdPartyVariable = 'bar'; } }]); ``` ## Use $apply to force a redraw of the page Angular doesn't watch $scope properties constantly for changes. This would be processing intensive. Instead, it has listeners for events like ng-click, ng-submit, etc. When these fire, Angular looks at the scopes to see if anything changes. If there's a change, Angular will call the $digest cycle, which basically means it will redraw the view. If you change a $scope property outside of the Angular environment (perhaps through a third party JS library), the view won't refresh. You can manually force the $digest cycle, though. To do this, simply call: ```javascript $scope.$apply(function(){ //once the code in here completes, force the $digest cycle to run }); ``` ### Example file: index.html ```html
{{foo}}
``` file: js/app.js ```javascript const app = angular.module('MyApp', []); app.controller('MainController', ['$scope', function($scope){ $scope.foo = 'foo'; document.querySelector('button').addEventListener('click', function(){ $scope.$apply(function(){ $scope.foo = 'bar'; }) }) }]); ```