Angularjs: как сделать ввод [текст] ngModel delay, оцененный при наборе текста

У меня есть текстовое поле с привязкой ngModel, например:

<input type="text" ng-model="typing" />

и значение этого texbox

value: {{ typing }}

Я хочу, чтобы задержка модели обновляла значение во время ввода. Возможно, если я остановлю тип в 500 мс, модель обновит все значение (все, что я набрал в текстовом поле). Я делаю некоторые Google, но не повезло. Кто-нибудь знает? пожалуйста, помогите.

ИЗМЕНИТЬ

Этот Angularjs: input [текст] ngChange срабатывает при изменении значения не дает решения для моего дела. Он приносит значение обновления решения после размытия, но мне нужно обновить значение после остановки печати, а не размывать текстовое поле.

РЕДАКТИРОВАТЬ 2 (Ответы)

В angular версии 1.4 директива ngModelOptions полезна в моем случае. Я могу написать как <input ng-model="typing" ng-model-options="{ updateOn: 'default', debounce: {'default': 500, 'blur': 0} }" />, чтобы отложить значение обновления до 500 мс по умолчанию и немедленно обновить, если потерял фокус.

Ответы

Ответ 1

Самый простой способ справиться с этим - это, вероятно, написать директиву, которая завершает элемент <input> и добавляет поведение задержки. Вот директива, которую я написал для этой же цели:

angular.module('MyModule')
    .directive('easedInput', function($timeout) {
        return {
            restrict: 'E',
            template: '<div><input class="{{externalClass}} my-eased-input" type="text" ng-model="currentInputValue" ng-change="update()" placeholder="{{placeholder}}"/></div>',
            scope: {
                value: '=',
                timeout: '@',
                placeholder: '@',
                externalClass: '@class'
            },
            transclude: true,
            link: function ($scope) {
                $scope.timeout = parseInt($scope.timeout);
                $scope.update = function () {
                    if ($scope.pendingPromise) { $timeout.cancel($scope.pendingPromise); }
                    $scope.pendingPromise = $timeout(function () { 
                        $scope.value = $scope.currentInputValue;
                    }, $scope.timeout);
                };
            }
        }
    });

Эта директива будет вызываться в вашем HTML так:

<eased-input value="myValue" timeout="500" placeholder="Please enter text..." />

Раскрытие директивы:

Служба тайм-аута

В этой директиве используется служба angular $timeout для обработки времени: это инъекционная, макетная, идиоматическая альтернатива вызову setTimeout. Эта служба вводится в конструктор директивы.

Атрибуты

Директива принимает три атрибута: value, timeout и placeholder.

Атрибут value здесь привязывается к переменной в области контроллера, которой принадлежит охватывающий "контекст". В этом случае он привязывается к myValue, то есть к $scope.myValue от того, какой контроллер отвечает за этот код. Он имеет двустороннюю привязку, обозначенную как запись '=' в свойстве scope директивы. Это означает, что когда эта директива обновляет value, изменение распространяется до контроллера, которому принадлежит директива; следовательно, $scope.myValue изменится, когда value будет изменено внутри директивы.

Атрибуты timeout и placeholder имеют односторонние привязки: директива считывает свои значения из атрибутов, но не изменяет их. Они представляют собой фактические значения конфигурации.

Шаблон HTML

Свойство template в директиве показывает HTML, который будет сгенерирован на своем месте после того, как angular скомпилирует и свяжет его. Это в основном просто элемент input с некоторыми специальными и не очень особенными атрибутами. Значение в поле ввода привязано к переменной currentInputValue в директиве $scope через ng-model. Событие change в поле ввода привязано к функции update в директиве $scope с помощью директивы ng-change.

Функция связи

Гиты процесса лежат в функции link в директиве: мы определяем метод update. Как указано выше, этот метод связан с событием change поля ввода в шаблоне HTML-схемы. Таким образом, каждый раз, когда пользователь меняет ввод в поле, вызывается update.

Этот метод использует службу $timeout. Он сообщает службе $timeout ждать timeout миллисекунд, а затем применить обратный вызов, который устанавливает $scope.value = $scope.currentInputValue. Это похоже на вызов setTimeout(function () {$scope.value = $scope.currentInputValue}, timeout).

Вызов $timeout возвращает обещание. Мы можем отменить обещание p, созданное $timeout, которое ожидает выполнения, вызывая $timeout.cancel(p). Это то, что update делает в своей первой строке: если у нас есть обещание от предыдущего события изменения, мы отменяем его перед созданием нового. Это означает, что если мы имеем, например, тайм-аут в 500 мс, а обновление вызывается дважды, при этом разнесение на 400 мс, у нас будет только одно обещание, ожидающее пожара.

Общий результат

Обещание при разрешении устанавливает $scope.value = currentInputValue; то есть он устанавливает свойство "внешне видимое" value, чтобы иметь значение содержимого поля ввода. value будет только изменяться - и внешние контроллеры будут видеть только изменение value - после периода покоя timeout миллисекунд, который, я считаю, является поведением, которое вы наблюдали после.

Ответ 2

Если вы согласны с наличием второго свойства в своей модели, вы можете использовать $scope.$watch вместе с функцией debounce:

HTML

<input type="text" ng-model="typing" />
<input type="text" value="{{ typed }}" />

Javascript

$scope.$watch('typing', debounce(function() {
    $scope.typed = $scope.typing;
    $scope.$apply();
}, 500));

Вы можете написать собственную функцию debounce или использовать существующую. Там хорошая реализация здесь, или, если вы используете undescore.js, вы уже настроены.

Вот пример jsFiddle.

UPDATE: Angular 1.3 теперь имеет встроенный способ для отладки пользовательского ввода: ngModelOptions.