การใช้ $watch เพื่ออัปเดตข้อมูล ng-repeat ไม่สะท้อนการเปลี่ยนแปลง

ฉันมีรายการอาหารใน $scope.raw และฉันต้องการแสดงข้อมูลนี้เป็นคอลัมน์ ดังนั้นฉันจึงเปลี่ยนโครงสร้างเล็กน้อย ฉันทำสิ่งนี้ในฟังก์ชัน sortStuff() และจัดเก็บข้อมูลที่อัปเดตไว้ใน $scope.allfood มี $watch ที่เรียก sortStuff() ทุกครั้งที่มีการเปลี่ยนแปลงใดๆ ใน $scope.raw (ฉันใช้การลากและวางเพื่อเปลี่ยนหมวดอาหาร):

$scope.$watch('raw', function(){
    $scope.allfood = $scope.sortStuff();
    console.log($scope.allfood);
}, true);

นี่คือสิ่งที่เกิดขึ้นเมื่อมีการลากอาหารไปมา:

receive:function(event, ui) {
    var issueScope = angular.element(ui.item).scope();
    scope.$apply(function() {
        var recp = _.find(scope.raw, function(lineitem){
            return lineitem.name === issueScope.receipe.name;
        })
        recp.cat = scope.col.name;
    })

    $(ui.item).remove(); // remove DOM
}

โดยพื้นฐานแล้ว ฉันจะค้นหาวัตถุที่ถูกต้องภายใน $scope.raw และเปลี่ยน cat เป็นหมวดหมู่ใหม่สำหรับอาหาร ฉันยังลบองค์ประกอบ dom ด้วยเพราะฉันต้องใช้ ng-repeat เพื่อรีเฟรชมุมมอง ดูเหมือนว่าจะทำงานได้ดี: console.log ภายใน $watch แสดงว่าวัตถุกำลังถูกย้ายไปยังหมวดหมู่ที่ถูกต้อง และข้อมูลจะมีลักษณะตามที่ควรจะเป็น อย่างไรก็ตาม หากมองด้วยสายตาแล้ว ng-repeat จะไม่สะท้อนถึงข้อมูล

นี่คือ jsfiddle

การลากรายการจาก B ไป C ทำงานได้ดี การลากอันหนึ่งจาก A ไป B ทำให้สองรายการจาก B หายไป... ผลลัพธ์ไม่สอดคล้องกันมาก และฉันไม่รู้ว่าเกิดอะไรขึ้น

มีความคิดอะไรเกิดขึ้นบ้าง? หรืออาจมีข้อเสนอแนะสำหรับวิธีที่ดีกว่าในการทำเช่นนี้?


person Community    schedule 08.12.2013    source แหล่งที่มา
comment
คุณควรใช้ $watchCollection('raw', function() {}); แต่ฉันได้ทำไปแล้วและยังคงพบปัญหาเดียวกันในแอปของฉัน...   -  person philwills    schedule 08.12.2013


คำตอบ (1)


ปัญหาเกี่ยวกับโค้ดของคุณคือคำสั่ง ng-repeat เพิ่มคุณสมบัติ $$hashKey ให้กับทุกองค์ประกอบในรายการ คุณสมบัตินี้ถูกใช้โดยคำสั่งในการเชื่อมโยงองค์ประกอบ DOM กับองค์ประกอบอาร์เรย์

เนื่องจากคุณกำลังส่งองค์ประกอบโดยการอ้างอิง คำสั่ง ng-repeat จะเขียนคุณสมบัติ $$hashKey ลงในอ็อบเจ็กต์ของอาร์เรย์ $scope.raw โดยตรง วิธีแก้ปัญหาง่ายๆ คือการคัดลอกออบเจ็กต์ก่อนที่จะแทรกลงในออบเจ็กต์ $scope.allfood

_.each($scope.raw, function(recp){
    recp = _.clone(recp);
    switch(recp.cat){
        ...
    }
});

ตอนนี้ ng-repeat อัปเดตออบเจ็กต์ของ $scope.allfood ในขณะที่ออบเจ็กต์ของ $scope.raw ยังคงไม่ถูกแตะต้อง

ดูซอที่อัปเดต:

http://jsfiddle.net/b8Fa7/5/

person Lorenz    schedule 08.12.2013
comment
ขอบคุณ มันได้ผล! สองคำถาม: เป็นไปได้ไหมที่จะโคลนวัตถุโดยไม่มีคุณสมบัติเช่น $$hashKey ที่เพิ่มด้วยเชิงมุม? คุณคิดว่ามีวิธีที่ดีกว่าในการทำเช่นนี้หรือไม่? ความจริงที่ว่าเชิงมุมสร้างใหม่ทั้งหมด $scope.allfood ในทุกการเปลี่ยนแปลงไม่สามารถส่งผลดีต่อประสิทธิภาพได้และฉันต้องการหลีกเลี่ยงมันด้วยวิธีใดวิธีหนึ่ง - person ; 08.12.2013
comment
angular.copy มีวิธีสร้างสำเนาเชิงลึกของอาร์เรย์หรืออ็อบเจ็กต์โดยไม่มีคุณสมบัติ เช่น $$hashKey: docs Angularjs.org/api/ Angular.copy - person Lorenz; 09.12.2013
comment
คุณอาจติดตามการเปลี่ยนแปลงทั้งหมดในอาร์เรย์ $scope.raw และแก้ไขเฉพาะวัตถุ $scope.allfood ตามการเปลี่ยนแปลงที่ติดตามเท่านั้น ฉันไม่คิดว่าสิ่งนี้จะนำมาซึ่งการปรับปรุงประสิทธิภาพที่โดดเด่นตราบใดที่รายการยังน้อย - person Lorenz; 09.12.2013
comment
Angular.copy ทำสิ่งที่ฉันต้องการ ขอบคุณ! - person ; 09.12.2013