$ เฝ้าดูการเปลี่ยนแปลงข้อมูลในคำสั่งเชิงมุม


133

ฉันจะทริกเกอร์$watchตัวแปรในคำสั่งเชิงมุมได้อย่างไรเมื่อจัดการข้อมูลภายใน (เช่นการแทรกหรือลบข้อมูล) แต่ไม่ได้กำหนดอ็อบเจกต์ใหม่ให้กับตัวแปรนั้น

ฉันมีชุดข้อมูลง่ายๆที่กำลังโหลดจากไฟล์ JSON ตัวควบคุมเชิงมุมของฉันทำสิ่งนี้รวมทั้งกำหนดฟังก์ชันบางอย่าง:

App.controller('AppCtrl', function AppCtrl($scope, JsonService) {
    // load the initial data model
    if (!$scope.data) {
        JsonService.getData(function(data) {
            $scope.data = data;
            $scope.records = data.children.length;
        });
    } else {
        console.log("I have data already... " + $scope.data);
    }

    // adds a resource to the 'data' object
    $scope.add = function() {
        $scope.data.children.push({ "name": "!Insert This!" });
    };

    // removes the resource from the 'data' object
    $scope.remove = function(resource) {
        console.log("I'm going to remove this!");
        console.log(resource);
    };

    $scope.highlight = function() {

    };
});

ฉันมีสิ่ง<button>ที่เรียกว่า$scope.addฟังก์ชันอย่างถูกต้องและวัตถุใหม่จะถูกแทรกลงใน$scope.dataชุดอย่างถูกต้อง ตารางที่ฉันตั้งค่าจะอัปเดตทุกครั้งที่กดปุ่ม "เพิ่ม"

<table class="table table-striped table-condensed">
  <tbody>
    <tr ng-repeat="child in data.children | filter:search | orderBy:'name'">
      <td><input type="checkbox"></td>
      <td>{{child.name}}</td>
      <td><button class="btn btn-small" ng-click="remove(child)" ng-mouseover="highlight()"><i class="icon-remove-sign"></i> remove</button></td>
    </tr>
  </tbody>
</table>

อย่างไรก็ตามคำสั่งที่ฉันตั้งค่าเพื่อรับชม$scope.dataจะไม่ถูกเริ่มทำงานเมื่อทั้งหมดนี้เกิดขึ้น

ฉันกำหนดแท็กของฉันใน HTML:

<d3-visualization val="data"></d3-visualization>

ซึ่งเกี่ยวข้องกับคำสั่งต่อไปนี้ (ตัดแต่งเพื่อความมีเหตุผลของคำถาม):

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            });
        }
    }
});

ฉันได้รับ"I see a data change!"ข้อความในตอนเริ่มต้น แต่ไม่ได้รับหลังจากที่ฉันกดปุ่ม "เพิ่ม"

ฉันจะทริกเกอร์$watchเหตุการณ์ได้อย่างไรเมื่อฉันแค่เพิ่ม / ลบวัตถุออกจากdataวัตถุโดยไม่ได้รับชุดข้อมูลใหม่ทั้งหมดเพื่อกำหนดให้กับdataวัตถุ


5
เพียงเคล็ดลับสั้น ๆ หาก newValue เคยเท่ากับ 0 เท็จ "" หรือสิ่งอื่นใดที่คุณ "ฉันเห็นการเปลี่ยนแปลงข้อมูล!" จะไม่ยิง ตัวอย่างเช่นค่าเดิมเป็นจริงค่า newValue เป็นเท็จ ควรจะเพียงพอที่จะใช้ newValue ในนั้นนาฬิกานั้นจะถูกเรียกก็ต่อเมื่อมีการเปลี่ยนแปลงเท่านั้น ถ้าเป็นวัตถุมันจะถูกเรียกทันที
Mathew Berg

เคล็ดลับที่ดีขอบคุณ! ฉันจะเปลี่ยนifคำสั่ง
Evil Closet Monkey

คำตอบ:


219

คุณต้องเปิดใช้งานการตรวจสอบสิ่งสกปรกแบบลึก โดยค่าเริ่มต้นเชิงมุมจะตรวจสอบการอ้างอิงของตัวแปรระดับบนสุดที่คุณรับชมเท่านั้น

App.directive('d3Visualization', function() {
    return {
        restrict: 'E',
        scope: {
            val: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch('val', function(newValue, oldValue) {
                if (newValue)
                    console.log("I see a data change!");
            }, true);
        }
    }
});

ดูขอบเขต พารามิเตอร์ที่สามของฟังก์ชั่น $ watch ช่วยให้สามารถตรวจสอบสิ่งสกปรกได้ลึกหากตั้งค่าเป็นจริง

รับทราบว่าการตรวจสอบสกปรกลึกที่มีราคาแพง ดังนั้นหากคุณเพียงแค่ต้องการดูอาร์เรย์เด็กแทนที่จะdataดูตัวแปรทั้งหมดให้ดูตัวแปรโดยตรง

scope.$watch('val.children', function(newValue, oldValue) {}, true);

เวอร์ชัน 1.2.x เปิดตัว$ watchCollection

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

scope.$watchCollection('val.children', function(newValue, oldValue) {});

2
ทำงานได้ดี ขอบคุณ!
Evil Closet Monkey

1
ดีใจที่ได้ช่วยเหลือ ลองใช้ฟังก์ชั่น $ watch ต่อไปเนื่องจากนิพจน์ที่สามารถรับชมได้นั้นค่อนข้างหลากหลาย
Liviu T.

1
ขอบคุณที่สังเกตวิธีตรวจสอบเฉพาะอาร์เรย์แบบลึกเท่านั้น)
veritas

น่าเสียดายที่ฉันไม่สามารถโหวตได้มากกว่าหนึ่งครั้ง .. ฉันจะให้รางวัลกับคุณสำหรับ 2 ชั่วโมงที่ฉันหลงทางเพื่อหาสิ่งนั้น
Alex Arvanitidis

คำตอบที่ดีที่สุด
chovy

2

เพราะถ้าคุณต้องการที่จะเรียกข้อมูลของคุณกับลึกของมันคุณต้องผ่านการโต้แย้งที่ 3 trueของ listener.By ของคุณเริ่มต้นมันfalseและมัน meens ที่คุณทำงานจะเรียกเฉพาะเมื่อคุณตัวแปรจะเปลี่ยนไม่ได้ข้อมูลของมัน


1

เวอร์ชันของฉันสำหรับคำสั่งที่ใช้ jqplot เพื่อพล็อตข้อมูลเมื่อพร้อมใช้งาน:

    app.directive('lineChart', function() {
        $.jqplot.config.enablePlugins = true;

        return function(scope, element, attrs) {
            scope.$watch(attrs.lineChart, function(newValue, oldValue) {
                if (newValue) {
                    // alert(scope.$eval(attrs.lineChart));
                    var plot = $.jqplot(element[0].id, scope.$eval(attrs.lineChart), scope.$eval(attrs.options));
                }
            });
        }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.