สิ่งที่ควรรู้
$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