Дебанд ng-model-options не работает на событии размытия, как ожидалось?

Я применил ng-model-options на input со следующей конфигурацией

ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}"

И согласно приложенной конфигурации к ng-model-options Я ожидаю обновления ng-model's значение на ng-blur событие, но оно не возвращает новое значение, несмотря на то, что установлено 0 значение debounce для события blur.

* Примечание: эта проблема возникает, только если пользователь сфокусировался раньше времени, указанного в default то есть 1000

HTML:

<input type="text" ng-model="myname" ng-blur="onBlur(myname)" ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}">
<input type="text" ng-model="output"/>

JS:

$scope.myname = "Yogesh";
$scope.output = "";
$scope.onBlur = function(a){
   $scope.output = a;
}

Плункерная ссылка: https://embed.plnkr.co/XJMUUD/

Почему debounce не работает? поправьте меня, если я что-то не так делаю!

Заранее спасибо:)

Я также дал ответ на мой вопрос! дайте мне знать, как это гибко использовать и как это поможет сократить циклы дайджеста событий.

3 ответа

Как ng-model-options поможет сократить циклы дайджеста событий?

Да, ng-model-options может помочь вам ограничить количество $digest циклы. Если бы вы использовали только ng-модель без установки каких-либо опций для нее, то ваш цикл $ digest будет выполняться для каждого изменения значения ng-модели. Если $digest цикл заполняется данными, подлежащими грязной проверке, пользователь увидит задержку в пользовательском интерфейсе, в то время как (например) печатает внутри. Вот пример из ссылки на блог toddmotto.

// app.js
angular
 .module('app', []);

function trackDigests($rootScope) {
    function link($scope, $element, $attrs) {
        var count = 0;
        function countDigests(newValue, oldValue) {
            count++;
            $element[0].innerHTML = '$digests: ' + count;
        }
        $rootScope.$watch(countDigests);
    }
    return {
        restrict: 'EA',
        link: link
    };
}

angular
 .module('app')
 .directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
    <div>
        <form name="myForm">
            <h3>Standard &lt;input&gt;</h3>
            <track-digests></track-digests>
            <input 
                   type="text" 
                   name="test" 
                   ng-model="test">
        </form>
    </div>
</div>

Как вы можете видеть из нашего стандартного ввода, $digest цикл запускается для каждого символа, который мы вводим в поле ввода. Это может вызвать задержку конечного пользователя для больших приложений.

Теперь мы увидим случай для входов с опциями ng-модели.

// app.js
angular
 .module('app', []);

function trackDigests($rootScope) {
    function link($scope, $element, $attrs) {
        var count = 0;
        function countDigests(newValue, oldValue) {
            count++;
            $element[0].innerHTML = '$digests: ' + count;
        }
        $rootScope.$watch(countDigests);
    }
    return {
        restrict: 'EA',
        link: link
    };
}

angular
 .module('app')
 .directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
    <div>
        <form name="myForm">
            <h3>ngModelOptions &lt;input&gt;</h3>
            <track-digests></track-digests>
            <input 
                   type="text" 
                   name="test" 
                   ng-model="test"
                   ng-model-options="{
                       updateOn: 'blur'
                   }">
        </form>
    </div>
</div>

Здесь мы можем видеть, что $digest Цикл срабатывает только тогда, когда мы теряем фокус с ввода. Итак, в основном ngModelOptions дают нам контроль над тем, как и когда $digest циклы происходят.

Давайте возьмем еще больший контроль над $digest цикл, вводя debounce, чтобы мы могли сказать угловые, когда обновлять.

// app.js
angular
 .module('app', []);

function trackDigests($rootScope) {
    function link($scope, $element, $attrs) {
        var count = 0;
        function countDigests(newValue, oldValue) {
            count++;
            $element[0].innerHTML = '$digests: ' + count;
        }
        $rootScope.$watch(countDigests);
    }
    return {
        restrict: 'EA',
        link: link
    };
}

angular
 .module('app')
 .directive('trackDigests', trackDigests);
<script src="//code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-app="app">
    <div>
        <form name="myForm">
            <h3>ngModelOptions &lt;input&gt;</h3>
            <track-digests></track-digests>
            <input 
                   type="text" 
                   name="test" 
                   ng-model="test"
                   ng-model-options="{
                       updateOn: 'default blur',
                       debounce: {
                           'default': 250,
                           'blur': 0
                       }
                   }">
        </form>
    </div>
</div>

Выше показано, что значение по умолчанию будет обновляться через 250 мс после прекращения события, и размытие будет обновляться немедленно, когда пользователь покидает ввод (если это желаемое поведение, которое мы хотим).

Начните вводить снова, затем остановитесь и отметьте $digest количество значительно ниже, чем первоначальная демонстрация. Затем вы можете нажать / вкладку, чтобы позвонить другому $digest немедленно.


В чем разница между дефолтом и изменением в debounce?

Значение по умолчанию и изменение свойства объектов debounce - это не что иное, как события. По умолчанию это не событие DOM, это просто часть API ng-model-options. Предположим, вы устанавливаете свои ngModelOptions как

ng-model-options="{
  updateOn: 'default'
}"

Тогда не будет никаких изменений в поведении вашего поля ввода по сравнению с поведением по умолчанию. Эта конфигурация не очень полезна, пока мы не объединим ее с

ng-model-options="{
  updateOn: 'default',
  debounce: { 'default': 500 }
}"

Это сделает ввод для обновления через 500 мс. Так что в основном это отвечает на то, что по умолчанию. Вы можете использовать другие события DOM, такие как change,blur,mouseover... и т. д. для вашего обсуждения.


Обновление:

Когда вы использовали ng-model-options="{updateOn:'default blur',debounce:{default:1000,blur:0}}", ng-blur было запущено со старым значением ng-модели, и после этого были запущены только события updateOn. Так что в основном выходные данные будут содержать старое значение ng-модели, хотя myname будет обновлено.

Рабочий пример: https://plnkr.co/edit/2JPHXvXd992JJ0s37YC9?p=preview

Теперь, когда вы использовали ng-model-options="{updateOn:'default change blur',debounce:{default:1000,blur:0,change:0}}", ng-blur было запущено с новым значением ng-model, потому что изменение настройки:0 заставляло события updateOn срабатывать до ng-blur.Таким образом, вывод был обновлен с новым значением ng-model вместе с myname.

Рабочий пример: https://plnkr.co/edit/9wdA0he2YVcsPRLJ1Ant?p=preview

После некоторых исследований мы столкнулись с этой конфигурацией

ng-model-options="{updateOn:'default change blur',debounce:{default:1000,blur:0,change:0}}"

Который работает отлично! как и ожидалось ng-blur Событие возвращает обновленное значение.

Это потому, что когда вы устанавливаете debounce Цикл дайджеста запускается по истечении заданного времени. После запуска дайджест-цикла проверяется, изменилось ли значение, которое еще не было синхронизировано в приложении.

В вашем случае входное значение будет синхронизировано с переменной модели myname через 1000 мс или 1 с, но немедленное обновление при снятии фокуса. Ваш метод onBlur(myname) вызывается с предыдущим значением mynameпотому что в то время, когда была вызвана функция, ей по-прежнему передается предыдущее значение аргумента (она не может обновить значение myname и одновременно вызывать функцию), и после этого обновление цикла дайджеста myname, Вы можете проверить, что модель обновляется немедленно, поставив {{myname}} рядом с входами.

ng-blur 
   -> call onBlur(myname)
      -> here myname is with old value still
      -> trigger digest loop (here is where the new value is assigned to myname) 
         -> update model & view

{updateOn: 'event'} указывает, что привязка должна происходить, когда происходит конкретное событие.

Чтобы обновить модель до того, как ваш элемент потеряет фокус (onblur), вы должны использовать updateOn: change и установите его время равным 0, вот так при каждом изменении angular немедленно свяжет новое значение с параметром вашей функции.

Другие вопросы по тегам