AngularJS에서 모델 변경을 볼 때 초기로드를 어떻게 무시합니까?


184

단일 엔티티의 편집기 역할을하는 웹 페이지가 있는데 $ scope.fieldcontainer 속성에 깊은 그래프로 표시됩니다. $ resource를 통해 REST API에서 응답을 얻은 후 'fieldcontainer'에 시계를 추가합니다. 이 시계를 사용하여 페이지 / 엔티티가 "더러운"것인지 감지합니다. 지금은 저장 버튼을 바운스하지만 실제로 사용자가 모델을 더럽힐 때까지 저장 버튼을 보이지 않게하고 싶습니다.

내가 얻는 것은 시계의 단일 트리거입니다. 시계가 생성 된 직후 .fieldcontainer = ... 할당이 발생하기 때문에 발생한다고 생각합니다. 나는 "dirtyCount"속성을 사용하여 초기 허위 경보를 흡수하려고 생각했지만 매우 해키 느낌이 들었습니다 ... 그리고 이것을 처리하는 "각도 관용적"방법이 있어야한다고 생각했습니다-나는 유일한 사람이 아닙니다. 더러운 모델을 감지하기 위해 시계를 사용합니다.

시계를 설정 한 코드는 다음과 같습니다.

 $scope.fieldcontainer = Message.get({id: $scope.entityId },
            function(message,headers) {
                $scope.$watch('fieldcontainer',
                    function() {
                        console.log("model is dirty.");
                        if ($scope.visibility.saveButton) {
                            $('#saveMessageButtonRow').effect("bounce", { times:5, direction: 'right' }, 300);
                        }
                    }, true);
            });

"if (dirtyCount> 0)"으로 "UI dirtying"코드를 보호하는 것보다이 작업을 수행하는 더 확실한 방법이 있어야한다고 생각합니다.


또한 특정 버튼을 기반으로 $ scope.fieldcontainer를 다시로드 할 수 있어야합니다 (예 : 이전 버전의 엔티티로드). 이를 위해서는 시계를 일시 중단하고 다시로드 한 다음 시계를 다시 시작해야합니다.
Kevin Hoffman 2016 년

내 답변을 수락 된 답변으로 변경 하시겠습니까? 끝까지 읽는 데 시간이 걸리는 사람들은 그것이 올바른 해결책이라는 데 동의하는 경향이 있습니다.
trixtur

@trixtur 나는 같은 OP 문제가 있지만 내 경우에는 이전 값이 아니기 때문에 대답이 작동하지 않습니다 undefined. 내 모델 업데이트가 모든 정보를 제공하지 않는 경우 필요한 기본값이 있습니다. 따라서 일부 값은 변경되지 않지만 트리거되어야합니다.
oliholz ​​2016 년

@oliholz ​​따라서 정의되지 않은 것을 검사하는 대신 "typeof"를 꺼내고 old_fieldcontainer를 기본값과 비교하여 점검하십시오.
trixtur

@KevinHoffman 당신은이 질문을 찾는 다른 사람들을 위해 정답에 MW의 답변을 표시해야합니다. 훨씬 더 나은 솔루션입니다. 감사!
Dev01

답변:


118

초기로드 직전에 플래그를 설정하고

var initializing = true

그런 다음 첫 $ watch가 실행되면

$scope.$watch('fieldcontainer', function() {
  if (initializing) {
    $timeout(function() { initializing = false; });
  } else {
    // do whatever you were going to do
  }
});

현재 다이제스트주기가 끝날 때 플래그가 해제되므로 다음 변경 사항이 차단되지 않습니다.


17
그렇습니다.하지만 @MW가 제안한 기존 및 새로운 가치 접근 방식을 비교하면 효과가 있습니다. 더 단순하고 각진 관용적입니다. 허용 된 답변을 업데이트 할 수 있습니까?
gerryster

2
처음 불이 플래그를 해킹 할 것을 피하기 위해 특별히 추가 된에 항상 NEWVALUE 동일하기 oldValue입니다 설정
찰리 마틴

2
이전 값에 대한 새 값이 이전 값이 정의되지 않은 경우를 처리하지 않으므로 MW의 대답은 실제로 올바르지 않습니다.
trixtur

1
주석가들에게 : 이것은 신 모델이 아니며, 데코레이터의 범위 안에 '초기화'변수를 넣은 다음 "정상"시계를 장식하는 것을 막을 수있는 것은 없습니다. 어쨌든 그것은이 질문의 범위를 완전히 벗어납니다.
다시 작성

1
.get () 콜백에서 감시자를 설정하고 범위를 초기화하는 방법을 모두 비교 한 방법에 대한 비교는 plnkr.co/edit/VrWrHHWwukqnxaEM3J5i 를 참조하십시오 .
다시 작성

483

리스너를 처음 호출하면 이전 값과 새 값이 동일합니다. 그래서 그냥 이렇게하십시오 :

$scope.$watch('fieldcontainer', function(newValue, oldValue) {
  if (newValue !== oldValue) {
    // do whatever you were going to do
  }
});

이것은 실제로 Angular 문서가 처리를 권장하는 방식입니다 .

감시자가 범위에 등록되면 리스너 fn이 비동기 적으로 ($ evalAsync를 통해) 호출되어 감시자를 초기화합니다. 드문 경우지만 watchExpression의 결과가 변경되지 않았을 때 리스너가 호출되므로 바람직하지 않습니다. 리스너 fn 내에서이 시나리오를 감지하기 위해 newVal과 oldVal을 비교할 수 있습니다. 이 두 값이 동일하면 (===) 초기화로 인해 리스너가 호출되었습니다.


3
이 방법은
@rewritten

25
이것은 정확하지 않습니다. 포인트는 null초기로드 된 값으로의 변경을 무시하고 변경이 없을 때 변경을 무시하지 않습니다.
다시 작성

1
리스너 기능은 시계가 만들어 질 때 항상 트리거됩니다. 이것은 그 첫 번째 부름을 무시합니다. 이것이 제가 아스카가 원했던 것이라고 생각합니다. 이전 값이 null 일 때 변경 사항을 무시하고 싶다면 oldValue를 null과 비교할 수는 있지만 그가 원하는 것을 생각하지 않습니다.
MW.

OP는 특히 REST 서비스에서 자원에 대한 감시자에 대해 묻습니다. 리소스가 먼저 생성 된 다음 감시자가 적용되고 응답의 특성이 기록되고 Angular 만 순환합니다. "초기화"플래그를 사용하여 첫 번째주기를 건너 뛰면 초기화 된 자원에만 감시자를 적용 할 수 있지만 여전히 /에서 변경 사항을 감시 할 수 null있습니다.
다시 작성

7
이것은 잘못된 oldValue것입니다. 첫 번째 둘러보기에서 null입니다.
Kevin C.

42

이 질문에 대한 답변을 받았지만 제안 사항이 있습니다.

$scope.$watch('fieldcontainer', function (new_fieldcontainer, old_fieldcontainer) {
    if (typeof old_fieldcontainer === 'undefined') return;

    // Other code for handling changed object here.
});

플래그를 사용하면 효과가 있지만 약간의 코드 냄새납니다 .


1
이것은 갈 길입니다. Coffeescript에서 return unless oldValue?(?는 CS의 실재 연산자입니다) 만큼 간단 합니다.
Kevin C.

1
단어 코드에 소품이 냄새! 또한 신 개체 롤을 확인하십시오. 너무 좋은.
Matthew Harwood

1
이것은 받아 들일만한 대답은 아니지만 API에서 객체를 채울 때 코드가 작동하도록하고 다른 저장 상태를보고 싶습니다. 아주 좋아요
Lucas Reppe Welander 2016

1
고마워-이것은 나를 위해 도움이되었습니다
완드 메이커

1
이것은 훌륭하지만 내 경우에는 API에 대한 AJAX 호출을 수행하기 전에 빈 배열로 데이터를 인스턴스화 했으므로 유형 대신 길이를 확인하십시오. 그러나이 답변은 적어도 가장 효과적인 방법을 보여줍니다.
Saborknight

4

현재 값을 처음로드하는 동안 이전 값 필드는 정의되지 않습니다. 따라서 아래 예제는 초기로드를 제외하는 데 도움이됩니다.

$scope.$watch('fieldcontainer', 
  function(newValue, oldValue) {
    if (newValue && oldValue && newValue != oldValue) {
      // here what to do
    }
  }), true;

당신은 아마 사용하려면! == 이후 nullundefined이 상황에서 일치, 또는 것 ( '1' == 1등)
제이미 페이트

일반적으로 당신이 맞습니다. 그러나이 경우 newValue 및 oldValue는 이전 검사로 인해 그러한 코너 값이 될 수 없습니다. 동일한 필드에 속하기 때문에 두 값의 유형도 동일합니다. 감사합니다.
Tahsin Turkoz

3

새 val의 상태 만 유효합니다.

$scope.$watch('fieldcontainer',function(newVal) {
      if(angular.isDefined(newVal)){
          //Do something
      }
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.