Menggunakan $watch untuk memperbarui data, ng-repeat tidak mencerminkan perubahan

Saya memiliki daftar makanan di $scope.raw dan saya ingin menampilkan data ini dalam kolom jadi saya mengubah strukturnya sedikit. Saya melakukan ini di fungsi sortStuff() dan menyimpan data yang diperbarui di $scope.allfood. Ada $watch yang memanggil sortStuff() setiap kali ada perubahan di $scope.raw (Saya menggunakan drag and drop untuk mengubah kategori makanan):

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

Inilah yang terjadi jika makanan diseret:

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
}

Pada dasarnya, saya mencari objek yang tepat di dalam $scope.raw dan mengubah cat ke kategori baru untuk makanan tersebut. Saya juga menghapus elemen dom karena saya mengandalkan ng-repeat untuk menyegarkan tampilan. Tampaknya ini berfungsi dengan baik: console.log di dalam $watch menunjukkan bahwa objek dipindahkan ke kategori yang tepat dan datanya terlihat seperti apa seharusnya. Namun, secara visual, ng-repeat tidak mencerminkan data.

Ini jsfiddle.

Menyeret item dari B ke C berfungsi dengan baik. Menyeret satu dari A ke B, membuat dua item dari B menghilang... hasilnya sangat tidak konsisten dan saya tidak tahu apa yang terjadi.

Ada ide apa yang salah? Atau mungkin ada saran cara yang lebih baik untuk melakukan ini?


person Community    schedule 08.12.2013    source sumber
comment
Anda harus menggunakan $watchCollection('raw', function() {}); tapi saya sudah melakukannya dan masih melihat masalah yang sama di aplikasi saya...   -  person philwills    schedule 08.12.2013


Jawaban (1)


Masalah dengan kode Anda adalah direktif ng-repeat menambahkan properti $$hashKey ke setiap elemen dalam daftar. Properti ini digunakan oleh direktif untuk mengaitkan elemen DOM dengan elemen array.

Karena Anda meneruskan elemen dengan referensi, direktif ng-repeat menulis properti $$hashKey langsung ke objek array $scope.raw Anda. Solusi sederhananya adalah dengan menyalin objek sebelum memasukkannya ke dalam objek $scope.allfood.

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

Sekarang ng-repeat memperbarui objek $scope.allfood, sedangkan objek $scope.raw tetap tidak tersentuh.

Lihat biola yang diperbarui:

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

person Lorenz    schedule 08.12.2013
comment
Terima kasih, itu berhasil! Namun ada dua pertanyaan: apakah mungkin untuk mengkloning objek tanpa properti seperti $$hashKey yang ditambahkan oleh sudut? Selain itu, menurut Anda apakah ada cara yang lebih baik untuk melakukan ini? Fakta bahwa sudut membuat ulang seluruh $scope.allfood pada setiap perubahan tidak baik untuk kinerja dan saya ingin menghindarinya. - person ; 08.12.2013
comment
angular.copy menyediakan cara untuk membuat salinan mendalam dari array atau objek tanpa properti seperti $$hashKey: docs. Angularjs.org/api/angular.copy - person Lorenz; 09.12.2013
comment
Anda mungkin dapat melacak semua perubahan pada array $scope.raw dan hanya memodifikasi objek $scope.allfood berdasarkan perubahan yang dilacak. Saya rasa hal ini tidak membawa peningkatan kinerja yang signifikan selama daftarnya kecil. - person Lorenz; 09.12.2013
comment
sudut.copy melakukan apa yang saya butuhkan. Terima kasih! - person ; 09.12.2013