$ 객체를보고


317

사전의 변경 사항을보고 싶지만 어떤 이유로 시계 콜백이 호출되지 않습니다.

내가 사용하는 컨트롤러는 다음과 같습니다.

function MyController($scope) {
    $scope.form = {
        name: 'my name',
        surname: 'surname'
    }

    $scope.$watch('form', function(newVal, oldVal){
        console.log('changed');
    });
}

여기 바이올린이 있습니다.

이름이나 성이 변경 될 때마다 $ watch 콜백이 시작될 것으로 예상되지만 발생하지는 않습니다.

올바른 방법은 무엇입니까?


답변:


570

전화 $watchtrue세 번째 인수로 :

$scope.$watch('form', function(newVal, oldVal){
    console.log('changed');
}, true);

자바 스크립트에서 두 개의 복잡한 객체를 비교할 때 기본적으로 "참조"동등성을 검사합니다. 이는 "두"개체가 "값"동등이 아닌 동일한 것을 참조 하는지를 묻습니다. 객체가 동일합니다.

각도 문서 , 세 번째 매개 변수는있다 objectEquality:

일 때 objectEquality == truewatchExpression의 부등식은 angular.equals기능 에 따라 결정됩니다 . 나중에 비교하기 위해 객체의 값을 저장하기 위해 angular.copy함수가 사용됩니다. 따라서 복잡한 객체를 시청하면 메모리와 성능에 부정적인 영향을 미칩니다.


2
이것은 좋은 대답이지만, 재귀 적으로 객체를보고 싶지 않을 때가 있다고 생각합니다.
Jason

16
있습니다. 기본적으로을 전달하지 않으면 true감시 된 값이 객체 또는 배열인지 여부에 따라 참조가 동일한 지 확인합니다. 이 경우에는 같은 명시 적 속성을 지정해야 $scope.$watch('form.name')하고$scope.$watch('form.surname')
rossipedia

3
감사. 바로 내가 놓친 것입니다. Jason, 당신 말이 맞아요. 당신은 항상 재귀 객체를보고 싶지는 않지만 제 경우에는 정확히 내가 필요했습니다.
Vladimir Sidorenko

1
변경 불가능한 JS 및 참조 비교는 성능 향상에 도움이 될 수 있습니다.
Dragos Rusu

13

form객체 만, 변경되지 않는 name속성입니다

바이올린 업데이트

function MyController($scope) {
$scope.form = {
    name: 'my name',
}

$scope.changeCount = 0;
$scope.$watch('form.name', function(newVal, oldVal){
    console.log('changed');
    $scope.changeCount++;
});
}

12

누군가가 키-> 값 쌍을 가진 데이터 스토어 종류의 서비스를 가지고 있다면 성능 팁 이 거의 없습니다 .

dataStore 라는 서비스가있는 경우 빅 데이터 객체가 변경 될 때마다 타임 스탬프를 업데이트 할 수 있습니다 . 이 방법으로 전체 개체를 자세히 보지 않고 변경 타임 스탬프 만보고 있습니다.

app.factory('dataStore', function () {

    var store = { data: [], change: [] };

    // when storing the data, updating the timestamp
    store.setData = function(key, data){
        store.data[key] = data;
        store.setChange(key);
    }

    // get the change to watch
    store.getChange = function(key){
        return store.change[key];
    }

    // set the change
    store.setChange = function(key){
        store.change[key] = new Date().getTime();
    }

});

그리고 지시에서 당신은 단지 타임 스탬프가 바뀌는 것을보고 있습니다

app.directive("myDir", function ($scope, dataStore) {
    $scope.dataStore = dataStore;
    $scope.$watch('dataStore.getChange("myKey")', function(newVal, oldVal){
        if(newVal !== oldVal && newVal){
            // Data changed
        }
    });
});

1
이 경우 저장하는 데이터의 이전 값에 액세스하는 기능을 잃어 버릴 것이라고 언급 할 가치가 있다고 생각합니다. newVal, oldVal이 예에서, 타임 스탬프 값이 아닌 물체 관측 값이다. 이 답변이 유효하지는 않지만 언급 할 가치가있는 단점이라고 생각합니다.
Michał Schielmann

사실,이 방법은 복잡한 데이터 구조를 소스 (예 : 일부 데이터의 새 버전)로로드하려고 할 때 주로 사용합니다. 내가 새롭고 오래된 값에 관심이 있다면 큰 복잡한 객체에 저장하지 않고 오히려 내가 관심있는 것의 작은 텍스트 표현을 가지고 변경을 위해 그것을 보거나 타임 스탬프가 변경 될 때 가져옵니다.
Ferenc Takacs

5

코드가 작동하지 않는 이유 $watch는 기본적으로 참조 확인을 수행 하기 때문 입니다. 간단히 말해 전달 된 객체가 새로운 객체인지 확인하십시오. 그러나 귀하의 경우 양식 객체의 일부 속성을 수정하여 새 속성을 만들지 않습니다. 작동시키기 위해 true세 번째 매개 변수로 전달할 수 있습니다 .

$scope.$watch('form', function(newVal, oldVal){
    console.log('invoked');
}, true);

작동하지만 $ watchCollection을 사용하면 $watchCollection양식 객체에서 얕은 속성을 볼 수 있기 때문에 $ watch보다 효율적 입니다. 예 :

$scope.$watchCollection('form', function (newVal, oldVal) {
    console.log(newVal, oldVal);
});

4

양식 객체 변경을 찾고있을 때 가장 좋은 시청 방법은을 사용하는 것
$watchCollection입니다. 다양한 성능 특성에 대한 공식 문서 를 살펴보십시오 .


1

이 시도:

function MyController($scope) {
    $scope.form = {
        name: 'my name',
        surname: 'surname'
    }

    function track(newValue, oldValue, scope) {
        console.log('changed');
    };

    $scope.$watch('form.name', track);
}

0

객체 배열 내에서 객체의 변경 사항을보고 싶은 사람에게는이 페이지의 다른 솔루션이 효과가 없었기 때문에 이것이 효과가있는 것처럼 보입니다.

function MyController($scope) {

    $scope.array = [
        data1: {
            name: 'name',
            surname: 'surname'
        },
        data2: {
            name: 'name',
            surname: 'surname'
        },
    ]


    $scope.$watch(function() {
        return $scope.data,
    function(newVal, oldVal){
        console.log(newVal, oldVal);
    }, true);

-3

$ watch ...에서 변경해야합니다.

function MyController($scope) {
    $scope.form = {
        name: 'my name',
    }

    $scope.$watch('form.name', function(newVal, oldVal){
        console.log('changed');
     
    });
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app>
    <div ng-controller="MyController">
        <label>Name:</label> <input type="text" ng-model="form.name"/>
            
        <pre>
            {{ form }}
        </pre>
    </div>
</div>


8
기존 질문과 거의 동일한 답변으로 2 년 된 질문에 대답하고 있습니까? 쿨하지 않아.
Jared Smith
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.