You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

201 lines
5.0 KiB

# 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
<!DOCTYPE html>
<html >
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js'></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body ng-app="MyApp">
<main ng-controller="MainController as main">
{{somevar}}
<button ng-click="main.changeScopeVar();">Click Me</button>
</main>
</body>
</html>
```
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
<!DOCTYPE html>
<html >
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js'></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body ng-app="MyApp">
<main ng-controller="MainController as main">
{{somevar}}
<button ng-click="main.changeScopeVar();">Click Me</button>
</main>
</body>
</html>
```
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
<!DOCTYPE html>
<html >
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js'></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body ng-app="MyApp">
<main ng-controller="MainController as main">
<button ng-click="main.clickFunction()">Click Me</button>
</main>
</body>
</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
<!DOCTYPE html>
<html >
<head>
<script src='https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js'></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body ng-app="MyApp">
<main ng-controller="MainController as main">
{{foo}}
<button>Click Me</button>
</main>
</body>
</html>
```
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';
})
})
}]);
```