Поведение по умолчанию для обновления ngModel (и последующая проверка) находится на смене; Я хотел бы изменить это на размытие. docs объясняют, как это сделать в каждом конкретном случае с помощью: <ANY ng-model-options="{ updateOn: 'blur' }"></ANY>
. Я зашел так далеко, чтобы посмотреть через исходный код, но почему-то не найдены ни ngModelOptions, ни ng-model-options (несмотря на то, что они встречаются в документации, которая очищается от исходного кода).
AngularJS устанавливает глобальные ngModelOptions
Ответ 1
В то время как декораторы ngModel
, написанные Джоном/Джоном, хорошо подходят для решения сцены, нужно также знать, что декларативно ngModelOptions
необязательно должно быть объявлено на отдельном уровне поля ввода, но может быть объявлено в уровень модуля.
<body ng-app = "myApp" ng-model-options="{ updateOn: 'blur' }">
Выполнение вышеуказанного будет иметь все поля ввода в модуле myApp
, наследующие параметры ng-model.
Затем они могут быть переопределены в определенных полях ввода, если это необходимо (например, фильтры поиска).
Этот плункер демонстрирует: http://plnkr.co/edit/2L1arGgHJwK82xVucJ4p?p=preview
Ответ 2
Как упоминает @Angad, вы можете установить ng-model-options для любого элемента, и он будет применяться ко всем его потомкам. Однако проблема заключается в том, что если вы установите его так, радио и флажки перестанут работать, как ожидалось:
<body ng-app="myApp" ng-model-options="{ updateOn: 'blur' }">
Это можно обойти, добавив change
и click
к updateOn
:
<body ng-app="myApp" ng-model-options="{ updateOn: 'change click blur' }">
Если вы также захотите обновить после некоторой задержки после ввода, вы можете использовать следующее:
<body ng-app="myApp" ng-model-options="{ updateOn: 'keyup change click blur', debounce: { keyup: 500, click: 0, change: 0, blur: 0 } }">
Я тестировал эти методы в Firefox, Chome, Internet Explorer (10, 11) и Safari. Если вы используете другие события, то, не забудьте проверить его кросс-браузер, например, fireos fire change
непосредственно после нажатия, во всех браузерах, кроме IE.
Ответ 3
Это действительно хороший вопрос, поэтому я написал более подробную информацию в этой статье. Единственный реальный общий способ, с которым я столкнулся, - это украсить директиву ngModel, поскольку именно эта директива действительно использует ngModelOptions.
Если вы посмотрите на источник angular для директивы ngModel, у него есть функция предварительной ссылки, чтобы эффективно настроить ngModelOptions на ngModelController с помощью свойства $вариантов. Обратите внимание, что $options создается в ngModelOptionsDirective, который фактически равен $eval в атрибуте ng-model-options.
Что нам нужно сделать в нашем dg-модуле ngModel, после этой функции предварительной ссылки добавить значение по умолчанию для этого свойства $options, если оно undefined. Я предполагаю, что если разработчик явно установил ngModelOptions в вашем проекте, что они не хотят, чтобы он волшебным образом изменился! Поэтому мы будем устанавливать только значения по умолчанию, если свойство $options undefined.
Вот код:
(function (angular) {
'use strict';
angular.module('myAppOverridesModule').config(['$provide',
function ($provide) {
$provide.decorator('ngModelDirective', [
'$delegate',
function ($delegate) {
var directive = $delegate[0],
link = directive.link,
shouldSetBlurUpdateEvent = function (nodeName, inputType) {
// The blur event is only really applicable to input controls so
// we want to stick with the default events for selects, checkboxes & radio buttons
return nodeName.toLowerCase() === 'textarea' ||
(nodeName.toLowerCase() === 'input' &&
inputType.toLowerCase() !== 'checkbox' &&
inputType.toLowerCase() !== 'radio');
};
directive.compile = function () {
return function (scope, element, attrs, ctrls) {
var ngModelCtrl = ctrls[0];
link.pre.apply(this, arguments);
// if ngModelOptions is specified leave it unmodified as developer is explicitly setting it.
if (ngModelCtrl.$options === undefined && shouldSetBlurUpdateEvent(element[0].nodeName, element[0].type)) {
console.log('set');
ngModelCtrl.$options = {
updateOn: 'blur',
updateOnDefault: false
};
}
link.post.apply(this, arguments);
};
};
return $delegate;
}
]);
}
]);
}(angular));
UPDATE: я обновил код, чтобы игнорировать элементы выбора, флажки и переключатели, поскольку событие размытия не является для них оптимальным событием обновления.
Ответ 4
Я изменил ответ Jon Samwell, потому что я не мог заставить его работать.
Это переопределяет функцию компиляции ngModelDirective, сохраняя ссылку на нее, а затем возвращает функции pre/postLink w/calls к их оригиналам плюс наш дополнительный код переопределения.
Наслаждайтесь!
app.config(function($provide) {
$provide.decorator('ngModelDirective', function($delegate) {
var directive = $delegate[0],
link = directive.link,
shouldSetBlurUpdateEvent = function (nodeName, inputType) {
// The blur event is only really applicable to input controls so
// we want to stick with the default events for selects, checkboxes & radio buttons
return nodeName.toLowerCase() === 'textarea' ||
(nodeName.toLowerCase() === 'input' &&
inputType.toLowerCase() !== 'checkbox' &&
inputType.toLowerCase() !== 'radio');
};
// save a reference to the original compile function
var compileFn = directive.compile;
directive.compile = function () {
var link = compileFn.apply(this, arguments);
return {
pre: function ngModelPostLink(scope, element, attr, ctrls) {
if(!ctrls[2]) {
ctrls[2] = {};
}
var ngModelOptions = ctrls[2];
if (ngModelOptions.$options === undefined && shouldSetBlurUpdateEvent(element[0].nodeName, element[0].type)) {
ngModelOptions.$options = {
updateOn: 'blur',
updateOnDefault: false
};
}
link.pre.apply(this, arguments);
},
post: link.post
};
};
return $delegate;
});
});
Ответ 5
Вместо использования
ng-model-options="{ updateOn: 'blur' }
вы можете использовать
ng-model-options="{ debounce : { default : 500 } }"
и примените его к родительскому элементу в dom, например, к контейнеру div. Установленный выше параметр debounce
сообщает Angular только оценить правила проверки после 500 миллисекунд без активности.
Использование debounce
таким образом превосходит использование blur
, потому что размытие создает проблемы для радио и флажков при применении ко всей форме.
Параметр debounce - это целочисленное значение, которое заставляет обновление модели задерживать целое число миллисекунд. Это уменьшает частоту циклов $digest
, что приводит к тому, что приложение js потребляет меньше ресурсов, а также позволяет пользователю вводить время до применения правил проверки.
YearOfMoo.com рекомендует использовать blur и debounce вместе, как это
ng-model-options="{ debounce : { default : 500, blur : 0 } }"
Теперь значение модели и валидации применяются сразу же после того, как пользователь вымывается из поля. Это устанавливает время ожидания 0 мс для события размытия. Blur переопределяет значение по умолчанию.