ดูแอตทริบิวต์ $ scope หลายรายการ


คำตอบ:


586

เริ่มต้นจาก AngularJS 1.3 มีวิธีการใหม่ที่เรียกว่า$watchGroupการสังเกตชุดของการแสดงออก

$scope.foo = 'foo';
$scope.bar = 'bar';

$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
  // newValues array contains the current values of the watch expressions
  // with the indexes matching those of the watchExpression array
  // i.e.
  // newValues[0] -> $scope.foo 
  // and 
  // newValues[1] -> $scope.bar 
});

7
ความแตกต่างกับ $ watchCollection คืออะไร ('[a, b]')
Kamil Tomšík

28
ความแตกต่างคือคุณสามารถใช้อาร์เรย์ที่เหมาะสมแทนสตริงที่ดูเหมือนอาร์เรย์
Paolo Moretti

2
ฉันมีปัญหาที่คล้ายกัน แต่ใช้รูปแบบคอนโทรลเลอร์เป็น ในกรณีของฉันการแก้ไขประกอบด้วยการเพิ่มตัวแปรชื่อของตัวควบคุม:$scope.$watchGroup(['mycustomctrl.foo', 'mycustomctrl.bar'],...
morels

1
ดูเหมือนจะไม่เหมาะกับฉันใน Angular 1.6 ถ้าฉันใส่ log console ลงในฟังก์ชั่นฉันจะเห็นว่ามันทำงานเพียงครั้งเดียวด้วยnewValuesและoldValuesในundefinedขณะที่การดูคุณสมบัติแต่ละรายการทำงานตามปกติ
Alejandro García Iglesias

290

เริ่มต้นด้วย AngularJS 1.1.4 คุณสามารถใช้$watchCollection:

$scope.$watchCollection('[item1, item2]', function(newValues, oldValues){
    // do stuff here
    // newValues and oldValues contain the new and respectively old value
    // of the observed collection array
});

ตัวอย่างเสียงพลั่วที่นี่

เอกสารที่นี่


109
โปรดทราบว่าพารามิเตอร์แรกไม่ใช่อาร์เรย์ มันเป็นสตริงที่ดูเหมือนอาร์เรย์
MK Safi

1
ขอบคุณสำหรับสิ่งนี้. ถ้ามันเหมาะกับฉันฉันจะให้คุณพันเหรียญทอง - ของจริงแน่นอน :)
AdityaSaxena

5
เพื่อให้ชัดเจน (ใช้เวลาไม่กี่นาทีที่ฉันจะรู้ตัว) $watchCollectionมีจุดมุ่งหมายเพื่อส่งมอบวัตถุและให้นาฬิกาสำหรับการเปลี่ยนแปลงคุณสมบัติของวัตถุใด ๆ ในขณะที่$watchGroupมีวัตถุประสงค์เพื่อส่งอาร์เรย์ของคุณสมบัติส่วนบุคคลเพื่อรับการเปลี่ยนแปลง แตกต่างกันเล็กน้อยเพื่อแก้ไขปัญหาที่คล้ายกัน แต่แตกต่างกัน วุ้ย
Mattygabe

1
อย่างใดค่าใหม่และค่าเก่าจะเท่ากันเสมอเมื่อคุณใช้วิธีนี้: plnkr.co/edit/SwwdpQcNf78pQ80hhXMr
Mostruash

ขอบคุณ มันแก้ไขปัญหาของฉัน มีผลกระทบต่อประสิทธิภาพการทำงาน / ปัญหาการใช้ $ watch
Syed Nasir Abbas

118

$watch พารามิเตอร์แรกสามารถเป็นฟังก์ชันได้

$scope.$watch(function watchBothItems() {
  return itemsCombinedValue();
}, function whenItemsChange() {
  //stuff
});

หากค่าที่รวมกันสองค่าของคุณเป็นแบบง่ายพารามิเตอร์แรกจะเป็นเพียงการแสดงออกเชิงมุมตามปกติ ตัวอย่างเช่นชื่อและนามสกุล:

$scope.$watch('firstName + lastName', function() {
  //stuff
});

8
ดูเหมือนว่าจะเป็นกรณีใช้งานที่ร้องออกมาเพื่อรวมอยู่ในกรอบโดยค่าเริ่มต้น แม้แต่คุณสมบัติที่คำนวณได้ง่าย ๆ เช่นเดียวกับfullName = firstName + " " + lastNameต้องผ่านฟังก์ชั่นเป็นอาร์กิวเมนต์แรก (แทนที่จะเป็นนิพจน์อย่างง่าย'firstName, lastName') เชิงมุมนั้นทรงพลังมาก แต่ก็มีบางพื้นที่ที่สามารถเป็นมิตรกับนักพัฒนาได้มากขึ้นในรูปแบบที่ไม่ส่งผลต่อประสิทธิภาพหรือหลักการออกแบบ
XML

4
$ watch ใช้การแสดงออกเชิงมุมซึ่งประเมินจากขอบเขตที่เรียก $scope.$watch('firstName + lastName', function() {...})ดังนั้นคุณสามารถทำ คุณสามารถทำได้เพียงแค่นาฬิกาสองเรือน: function nameChanged() {}; $scope.$watch('firstName', nameChanged); $scope.$watch('lastName', nameChanged);. ฉันเพิ่มกรณีง่าย ๆ ในคำตอบ
Andrew Joslin

เครื่องหมายบวกใน 'firstName + นามสกุล' คือการต่อสตริง ดังนั้นเชิงมุมจะตรวจสอบว่าผลลัพธ์ของการต่อข้อมูลนั้นแตกต่างกันหรือไม่
mb21

16
การต่อข้อมูลสตริงต้องใช้ความระมัดระวัง - หากคุณเปลี่ยน "paran orman" เป็น "para norman" มากกว่าที่คุณจะไม่ตอบสนอง ดีที่สุดที่จะนำตัวแบ่งเช่น "\ t | \ t" ระหว่างภาคแรกและภาคที่สองหรือเพียงแค่ติดกับ JSON ซึ่งเป็นที่ชัดเจน
Dave Edelhart

แม้ว่า amberjs จะดูด แต่ก็มีคุณสมบัตินี้สร้างใน! ได้ยินพวกมุม ฉันเดาว่าการดูนาฬิกาเป็นวิธีที่มีเหตุผลที่สุด
Aladdin Mhemed

70

นี่คือวิธีการแก้ปัญหาที่คล้ายกับหลอกรหัสต้นฉบับของคุณที่ใช้งานได้จริง:

$scope.$watch('[item1, item2] | json', function () { });

แก้ไข:โอเคฉันคิดว่านี่จะดีกว่า:

$scope.$watch('[item1, item2]', function () { }, true);

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


ฉันมีคำถามที่คล้ายกัน และนี่คือคำตอบที่ถูกต้องสำหรับฉัน
Calvin Cheng

ทั้งสองมีค่าใช้จ่ายประสิทธิภาพเล็กน้อยหากรายการในนิพจน์อาเรย์ไม่ใช่ประเภทที่เรียบง่าย
null

นั่นเป็นความจริง .. มันกำลังทำการเปรียบเทียบเชิงลึกของวัตถุส่วนประกอบ ซึ่งอาจจะใช่หรือไม่ใช่อย่างที่คุณต้องการ ดูคำตอบที่ได้รับอนุมัติในปัจจุบันสำหรับเวอร์ชันที่ใช้มุมเชิงมุมที่ไม่ได้ทำการเปรียบเทียบเชิงลึกแบบสมบูรณ์
Karen Zilles

ด้วยเหตุผลบางอย่างเมื่อฉันพยายามใช้ $ watchCollection กับอาร์เรย์ฉันได้รับข้อผิดพลาดTypeError: Object #<Object> has no method '$watchCollection'นี้ แต่วิธีนี้ช่วยฉันแก้ปัญหาของฉันได้!
abottoni

เจ๋งคุณสามารถดูค่าภายในวัตถุ:$scope.$watch('[chaptercontent.Id, anchorid]', function (newValues, oldValues) { ... }, true);
Serge van den Oever

15

คุณสามารถใช้ฟังก์ชั่นใน $ watchGroup เพื่อเลือกฟิลด์ของวัตถุในขอบเขต

        $scope.$watchGroup(
        [function () { return _this.$scope.ViewModel.Monitor1Scale; },   
         function () { return _this.$scope.ViewModel.Monitor2Scale; }],  
         function (newVal, oldVal, scope) 
         {
             if (newVal != oldVal) {
                 _this.updateMonitorScales();
             }
         });

1
ทำไมคุณใช้_this? ขอบเขตไม่ได้ถูกนำไปใช้กับฟังก์ชั่นโดยไม่กำหนดอย่างชัดเจนหรือไม่?
sg.cc

1
ฉันใช้ typescript รหัสที่นำเสนอรวบรวมผล
หยางจาง

12

ทำไมไม่ห่อมันด้วยforEach?

angular.forEach(['a', 'b', 'c'], function (key) {
  scope.$watch(key, function (v) {
    changed();
  });
});

มันเป็นเรื่องของค่าใช้จ่ายเช่นเดียวกับการให้บริการฟังก์ชั่นสำหรับค่ารวมกัน, ไม่จริงต้องกังวลเกี่ยวกับองค์ประกอบค่า


ในกรณีนี้บันทึก () จะถูกดำเนินการหลายครั้งใช่มั้ย ฉันคิดว่าในกรณีที่ฟังก์ชั่นการเฝ้าดู $ ซ้อนกันมันจะไม่ และไม่ควรใช้วิธีแก้ปัญหาสำหรับการดูหลาย ๆ คุณสมบัติพร้อมกัน
John Doe

ไม่บันทึกจะถูกดำเนินการเพียงครั้งเดียวต่อการเปลี่ยนแปลงต่อคุณสมบัติที่ได้รับการตรวจสอบ เหตุใดจึงมีการเรียกใช้หลายครั้ง
Erik Aigner

ใช่ฉันหมายความว่ามันจะไม่ดีถ้าเราต้องการดูพวกเขาทั้งหมดพร้อมกัน
John Doe

1
แน่นอนว่าทำไมไม่ ฉันทำอย่างนั้นในโครงการของฉัน changed()ถูกเรียกใช้เมื่อใดก็ตามที่มีการเปลี่ยนแปลงบางอย่างในคุณสมบัติอย่างใดอย่างหนึ่ง นั่นเป็นพฤติกรรมที่แน่นอนเหมือนกับว่ามีการจัดหาฟังก์ชันสำหรับค่าที่รวมกัน
Erik Aigner

1
มันแตกต่างกันเล็กน้อยหากว่ามีหลายรายการในอาเรย์เปลี่ยนไปในเวลาเดียวกัน $ watch จะทำการสั่งการตัวจัดการเพียงครั้งเดียวแทนที่จะเปลี่ยนหนึ่งครั้งต่อรายการ
bingles

11

วิธีที่ปลอดภัยกว่าเล็กน้อยในการรวมค่าอาจจะใช้สิ่งต่อไปนี้เป็น$watchฟังก์ชั่นของคุณ:

function() { return angular.toJson([item1, item2]) }

หรือ

$scope.$watch(
  function() {
    return angular.toJson([item1, item2]);
  },
  function() {
    // Stuff to do after either value changes
  });

5

$ watch พารามิเตอร์ตัวแรกอาจเป็นนิพจน์หรือฟังก์ชันเชิงมุม ดูเอกสารเกี่ยวกับ$ ขอบเขต. $ นาฬิกา มันมีข้อมูลที่เป็นประโยชน์มากมายเกี่ยวกับวิธีการทำงานของ $ watch: เมื่อมีการเรียกใช้ watch expression การเปรียบเทียบผลเชิงมุมเป็นต้น


4

เกี่ยวกับ:

scope.$watch(function() { 
   return { 
      a: thing-one, 
      b: thing-two, 
      c: red-fish, 
      d: blue-fish 
   }; 
}, listener...);

2
หากไม่มีtrueพารามิเตอร์ตัวที่สามถึงscope.$watch(เช่นในตัวอย่างของคุณ) listener()จะเริ่มทำงานทุกครั้งเนื่องจากแฮชที่ไม่ระบุชื่อมีการอ้างอิงที่แตกต่างกันทุกครั้ง
ปีเตอร์ V. Mørch

ฉันพบว่าวิธีนี้ใช้ได้ผลกับสถานการณ์ของฉัน return { a: functionA(), b: functionB(), ... }สำหรับผมมันก็มากขึ้นเช่น: ฉันจะตรวจสอบวัตถุที่ถูกส่งคืนของค่าใหม่และเก่าซึ่งกันและกัน
RevNoah

4
$scope.$watch('age + name', function () {
  //called when name or age changed
});

ฟังก์ชั่นที่นี่จะได้รับการเรียกเมื่อทั้งอายุและมูลค่าของชื่อได้รับการเปลี่ยนแปลง


2
ตรวจสอบให้แน่ใจว่าในกรณีนี้อย่าใช้อาร์กิวเมนต์ newValue และ oldValue ที่มุมส่งผ่านไปยังการเรียกกลับเนื่องจากจะเป็นการเชื่อมต่อที่ได้ผลลัพธ์ไม่ใช่เฉพาะเขตข้อมูลที่เปลี่ยนไป
Akash Shinde

1

Angular นำมาใช้$watchGroupในเวอร์ชั่น 1.3 ซึ่งเราสามารถรับชมตัวแปรหลาย ๆ ตัวพร้อมกับ$watchGroupบล็อก เดียว$watchGroupจะใช้อาร์เรย์เป็นพารามิเตอร์แรกที่เราสามารถรวมตัวแปรทั้งหมดของเราเพื่อรับชม

$scope.$watchGroup(['var1','var2'],function(newVals,oldVals){
   console.log("new value of var1 = " newVals[0]);
   console.log("new value of var2 = " newVals[1]);
   console.log("old value of var1 = " oldVals[0]);
   console.log("old value of var2 = " oldVals[1]);
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.