Как игнорировать начальную загрузку при просмотре изменений модели в AngularJS?

У меня есть веб-страница, которая служит редактором для одного объекта, который сидит как глубокий граф в свойстве $scope.fieldcontainer. После получения ответа от моего REST API (через $resource), я добавляю часы в полевой контейнер. Я использую эти часы, чтобы определить, является ли страница/объект "грязной". Прямо сейчас я делаю откат кнопки сохранения, но на самом деле я хочу сделать кнопку сохранения невидимой, пока пользователь не сравнит модель.

То, что я получаю, является единственным триггером часов, который, как я думаю, происходит потому, что назначение .fieldcontainer =... происходит сразу после создания моих часов. Я думал о том, что просто использовал свойство "dirtyCount" для поглощения первоначальной ложной тревоги, но это очень опасно... и я подумал, что должен быть "Angular идиоматический" способ справиться с этим - я не только один, используя часы для обнаружения грязной модели.

Здесь код, где я устанавливаю часы:

 $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);
            });

Я просто продолжаю думать, что должен быть более чистый способ сделать это, чем защищать мой "грязный" код UI с помощью "if (dirtyCount > 0)"...

Ответ 1

установите флаг непосредственно перед начальной загрузкой,

var initializing = true

а затем, когда срабатывает первый $watch, do

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

Флаг будет разорван только в конце текущего цикла дайджеста, поэтому следующее изменение не будет заблокировано.

Ответ 2

При первом вызове слушателя старое значение и новое значение будут идентичны. Так что просто сделайте это:

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

На самом деле, именно так Angular docs рекомендует обращаться с этим:

После того, как наблюдатель зарегистрирован в области действия, слушатель fn вызывается асинхронно (через $ evalAsync) для инициализации наблюдателя. В редких случаях это нежелательно, потому что слушатель вызывается, когда результат watchExpression не изменился. Чтобы обнаружить этот сценарий в слушателе fn, вы можете сравнить newVal и oldVal. Если эти два значения идентичны (===), то слушатель был вызван из-за инициализации

Ответ 3

Я понимаю, что на этот вопрос был дан ответ, однако у меня есть предложение:

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

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

Использование флагов работает, но имеет немного запаха кода , как вы думаете?

Ответ 4

Просто введите состояние нового val:

$scope.$watch('fieldcontainer',function(newVal) {
      if(angular.isDefined(newVal)){
          //Do something
      }
});

Ответ 5

При начальной загрузке текущих значений старое значение поля undefined. Поэтому приведенный ниже пример поможет вам исключить начальные нагрузки.

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