AngularJS: ตรวจจับการเปลี่ยนแปลงในโมเดลโดยอัตโนมัติ


103

สมมติว่าฉันต้องการทำบางอย่างเช่นเรียกใช้โค้ดโดยอัตโนมัติ (เช่นการบันทึกข้อมูลลงในเซิร์ฟเวอร์) เมื่อใดก็ตามที่ค่าของโมเดลเปลี่ยนแปลง เป็นวิธีเดียวที่จะทำได้โดยการตั้งค่าบางอย่างเช่นng-changeในแต่ละคอนโทรลที่อาจเปลี่ยนโมเดลได้หรือไม่?

กล่าวคือด้วยมุมมองสิ่งต่างๆจะเปลี่ยนไปทันทีเมื่อโมเดลมีการเปลี่ยนแปลงโดยไม่ต้องเชื่อมโยงอะไรอย่างชัดเจน มีอะนาล็อกที่สามารถรันโค้ดที่บันทึกไปยังเซิร์ฟเวอร์ได้หรือไม่? สิ่งที่ต้องการ

myModel.on('change', function() {
  $.post("/my-url", ...);
});

อย่างที่คุณอาจเห็นเช่นกระดูกสันหลัง

คำตอบ:


151

ในมุมมองที่มี{{}}และ / หรือ ng-model Angular กำลังตั้งค่า$watch()สำหรับคุณอยู่เบื้องหลัง

โดยค่าเริ่มต้นจะ$watchเปรียบเทียบโดยการอ้างอิง ถ้าคุณตั้งค่าพารามิเตอร์ที่สามที่จะ$watchไปtrue, เชิงมุมจะแทน "ตื้น" ชมวัตถุสำหรับการเปลี่ยนแปลง สำหรับอาร์เรย์หมายถึงการเปรียบเทียบรายการอาร์เรย์สำหรับการแมปวัตถุหมายถึงการดูคุณสมบัติ ดังนั้นสิ่งนี้ควรทำในสิ่งที่คุณต้องการ:

$scope.$watch('myModel', function() { ... }, true);

อัปเดต : Angular v1.2 ได้เพิ่มวิธีการใหม่สำหรับสิ่งนี้`$ watchCollection () :

$scope.$watchCollection('myModel', function() { ... });

โปรดทราบว่าคำว่า "ตื้น" ใช้เพื่ออธิบายการเปรียบเทียบมากกว่า "ลึก" เนื่องจากไม่ได้ติดตามการอ้างอิง - เช่นหากวัตถุที่เฝ้าดูมีค่าคุณสมบัติที่อ้างอิงถึงวัตถุอื่นการอ้างอิงนั้นจะไม่ถูกนำไปเปรียบเทียบ วัตถุอื่น ๆ


1
อายอด! มีเหตุผลใดบ้างที่ดูเหมือนจะไม่เป็นเอกสารทั้งหมด (เช่นฉันไม่คิดว่าจะมีบทช่วยสอนใด ๆ ในไซต์เชิงมุมที่กล่าวถึงการตั้งค่านาฬิกา $ โดยตรง) มีอะไรที่ไม่ดีเกี่ยวกับเรื่องนี้ที่จะทำให้การตั้งค่าng-changehooks (อาจมีหลายอัน) ในการควบคุมอินพุตเป็นแนวคิดที่ดีกว่าหรือไม่?
Alec

12
ใช่มันจะดีถ้าบทแนะนำหลักกล่าวถึง $ watch ที่ไหนสักแห่ง สิ่งที่ "ไม่ดี" เกี่ยวกับแนวทางนี้คืออาจใช้เวลานานหากโมเดลของคุณมีขนาดใหญ่ (ทุกรอบการย่อย - ทุกการกดแป้นพิมพ์ในช่องป้อนข้อมูล - จะส่งผลให้โมเดลนี้ถูกตรวจสอบแบบสกปรกอย่างละเอียดอาจจะหลายครั้ง) . ในกรณีนั้นการเลือก $ watch () es หรือการเปลี่ยนแปลงแบบเลือกจะดีกว่า
Mark Rajcok

8

และหากคุณต้องการจัดรูปแบบองค์ประกอบของฟอร์มตามสถานะ (แก้ไข / ไม่แก้ไข) แบบไดนามิกหรือเพื่อทดสอบว่าค่าบางค่าเปลี่ยนแปลงไปจริงหรือไม่คุณสามารถใช้โมดูลต่อไปนี้ที่พัฒนาโดยตัวเอง: https://github.com/betsol / angular-input-modified

เพิ่มคุณสมบัติและวิธีการเพิ่มเติมให้กับแบบฟอร์มและเป็นองค์ประกอบลูก ด้วยวิธีนี้คุณสามารถทดสอบว่าองค์ประกอบบางส่วนมีข้อมูลใหม่หรือแม้กระทั่งทดสอบว่าทั้งฟอร์มมีข้อมูลใหม่ที่ยังไม่ได้บันทึกหรือไม่

คุณสามารถตั้งค่านาฬิกาต่อไปนี้: $scope.$watch('myForm.modified', handler)และตัวจัดการของคุณจะถูกเรียกหากองค์ประกอบของฟอร์มบางส่วนมีข้อมูลใหม่จริง ๆ หรือหากกลับสู่สถานะเริ่มต้น

นอกจากนี้คุณสามารถใช้modifiedคุณสมบัติขององค์ประกอบฟอร์มแต่ละรายการเพื่อลดปริมาณข้อมูลที่ส่งไปยังเซิร์ฟเวอร์ผ่านการโทร AJAX ไม่จำเป็นต้องส่งข้อมูลที่ไม่มีการเปลี่ยนแปลง

เป็นโบนัสคุณสามารถเปลี่ยนแบบฟอร์มของคุณกลับสู่สถานะเริ่มต้นโดยใช้reset()วิธีการโทรไปที่ฟอร์ม

คุณสามารถดูการสาธิตของโมดูลได้ที่นี่: http://plnkr.co/edit/g2MDXv81OOBuGo6ORvdt?p=preview

ไชโย!


มีวิธีตรวจสอบสิ่งนี้ในคอนโทรลเลอร์หรือไม่ ตัวอย่างเช่นหากคลิกปุ่ม x ฉันสามารถทำเช่น if (myform.modified) แสดงป๊อปอัปยืนยันได้หรือไม่
แฟลช

แน่นอนเพียงแค่ส่ง FormController ไปยังฟังก์ชันคอนโทรลเลอร์ของคุณ: <form name="myForm">, <button ng-click="vm.doSomething(myForm)">.
Slava Fomin II

ขอบคุณสิ่งนี้จะทำบางอย่างก็ต่อเมื่อมีการแก้ไขแบบฟอร์มใช่หรือไม่
แฟลช

สิ่งนี้จะส่งผ่านFormControllerไปยังdoSomething()ฟังก์ชันของคอนโทรลเลอร์ของคุณ คุณสามารถทำอะไรก็ได้ที่คุณต้องการภายในฟังก์ชันนั้นเช่นตรวจสอบว่าฟอร์มถูกแก้ไขจริงหรือไม่โดยการตรวจสอบFormController.modifiedคุณสมบัติบูลีน
Slava Fomin II

ขอบคุณ! คุณลักษณะที่ดี
Flash
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.