$digest() คือ อะไร ?

$digest เป็นฟังก์ชั่นที่ถูกเรียกทุกครั้งเมื่อมีการเปลี่ยนแปลงของข้อมูลใน scope ของ Controller โดยจะทำการประมวลผลของ Angular ใหม่

$digest จะทำงานอัตโนมัติ ไม่ต้องทำการเรียกใช้

$apply() คือ อะไร ?

$apply เป็นฟังก์ชั่นที่ใช้เมื่อต้องการใช้ javascript ใดๆที่อยู่นอกเหนือของ AngularJS

(DOM events, setTimeout, XHR or third party libraries)

โดยเมื่อ $apply ทำงานเสร็จจะไปเรียกใช้ $digest ให้ update เนื้อหาของ angular

$digest จะไม่ถูกเรียกใน directive หากไม่มีการใช้ $apply

โดยมีโครงสร้างดังนี้

$apply( expression/function );

ซึ่งภายในของ $apply มีลักษณะดังนี้

function $apply(expr) {
 try {
   return $eval(expr);
 } catch (e) {
   $exceptionHandler(e);
 } finally {
   $root.$digest();
 }
}

ตัวอย่างการใช้งาน $apply

ใน Directive ถ้าต้องการแสดงค่าที่เปลี่ยนแปลงไปจะต้องทำเรียก $apply() เพื่อที่ $apply() จะไปเรียก $digest() อีกที

ใน Controller $digest() ทำงานอัตโนมัติ

ในไฟล์ js กำหนดฟังก์ชั่นเปลี่ยนค่าเมื่อ click ใน controller และ directive โดยมีรายละเอียดดังนี้

angular.module('application', [])
    .controller('demoController', function ($scope) {
        $scope.foo = 0;
        $scope.bar = 0;
		$scope.addCount = function () {
			$scope.foo++;	
			$scope.bar++;	
		};
    })
    .directive('clickable', function () {
        return {
            restrict:'E',
            template: '<ul style="background-color: lightgreen"><li>{{foo}}</li><li>{{bar}}</li></ul>',
            link: function (scope,element,attr) {
                element.bind('click', function () {
                    scope.$apply(function () {
						scope.foo++;
						scope.bar++;
					});
                });
            }
        };
    });

ในไฟล์ html ทำการเรียกใช้งาน directive ใน Controller

<div ng-app="application" ng-controller="demoController" style="background-color: pink">
	<p ng-click="addCount()">controller (foo) : \{\{foo}}</p>
	<p ng-click="addCount()">controller (bar) : \{\{bar}}</p>
	<clickable></clickable>
</div>

จะได้ผลลัพธ์ดังนี้

controller (foo) : {{foo}}

controller (bar) : {{bar}}

เมื่อทำการคลิกที่ clickable เรียกใช้งาน $apply() ค่าที่เปลี่ยนแปลงจะถูกแสดงผล

ถ้าไม่ใส่ $apply() ละจะเกิดอะไรขึ้น

ในกรณีที่เอา $apply() ออกจากภายใน directive

angular.module('application', [])
    .controller('demoController', function ($scope) {
        ...
    })
    .directive('clickable', function () {
        return {
            restrict:'E',
            template: '<ul style="background-color: lightgreen"><li>{{foo}}</li><li>{{bar}}</li></ul>',
            link: function (scope,element,attr) {
                element.bind('click', function () {
                    scope.foo++;
                    scope.bar++;
                });
            }
        };
    });

เมื่อ click ใน Directive ค่าที่เปลี่ยนแปลงจะไม่ถูกแสดงผล

จะได้ผลลัพธ์ดังนี้

controller (foo) : {{foo}}

controller (bar) : {{bar}}

เมื่อทำการคลิกที่ข้อมูลใน Controller เกิดการเปลี่ยนแปลงของข้อมูล $digest() ถูกเรียกใช้ ค่าถูกแสดงผล

เมื่อทำการคลิกที่ข้อมูลใน clickable ค่าเปลี่ยนไป แต่ไม่ได้ถูกนำมาแสดงผล เพราะ $digest() ไม่ได้ถูกเรียกใน directive