Подтвердить что ты не робот

AngularJS устанавливает глобальные ngModelOptions

Поведение по умолчанию для обновления ngModel (и последующая проверка) находится на смене; Я хотел бы изменить это на размытие. docs объясняют, как это сделать в каждом конкретном случае с помощью: <ANY ng-model-options="{ updateOn: 'blur' }"></ANY>. Я зашел так далеко, чтобы посмотреть через исходный код, но почему-то не найдены ни ngModelOptions, ни ng-model-options (несмотря на то, что они встречаются в документации, которая очищается от исходного кода).

4b9b3361

Ответ 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 переопределяет значение по умолчанию.