Какова цель нового встроенного ключа проверки 'parse' в Angular 1.3?

По-видимому, поведение механизма синтаксического анализа ngModelController изменилось между Angular 1.2 и 1.3. Теперь я всегда вижу новый ключ проверки с именем 'parse', добавленный ко всем объектам $error, и всякий раз, когда один из парсеров возвращает undefined, он переопределяет/заменяет все другие ключи проверки, которые могут быть уже установлены.

Например, вот рабочий пример в Angular 1.2.23 - попробуйте ввести число вне диапазона:

http://jsfiddle.net/8doq0saf/5/

То же самое, что работает под 1.3-rc, дает другой результат:

http://jsfiddle.net/1t52s9b2/4/

Я еще не смог найти документацию об этом изменении. Какова цель ключа синтаксического анализа и как я могу изменить свой код, чтобы вернуть прежнее поведение?

angular.module('app', []).directive('number', function () {
    return {
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {

            // valid number
            ctrl.$parsers.push(function (value) {
                var valid = angular.isUndefined(value) || value === '' || isFinite(value);
                ctrl.$setValidity('number', valid);
                return valid
                    ? angular.isUndefined(value) || value === '' ? undefined : Number(value)
                    : undefined;
            });

            ctrl.$parsers.push(function (value) {
                if (!angular.isDefined(attrs.minNumber)) {
                    return value;
                }
                var valid = angular.isUndefined(value) || Number(value) >= Number(attrs.minNumber);
                ctrl.$setValidity('minNumber', valid);
                return valid ? value : undefined;
            });

            ctrl.$parsers.push(function (value) {
                if (!angular.isDefined(attrs.maxNumber)) {
                    return value;
                }
                var valid = angular.isUndefined(value) || Number(value) <= Number(attrs.maxNumber);
                ctrl.$setValidity('maxNumber', valid);
                return valid ? value : undefined;
            });
        }
    };
});

Ответ 1

Angular 1.3 рационализированные вещи, чтобы сделать чистое различие между синтаксическим разбором и валидацией.

Синтаксический

Angular теперь автоматически добавляет ключ "parse" ко всем коллекциям $error с соответствующим значением, установленным соответственно - true, если какой-либо из парсеров возвратил undefined, false в противном случае.

Для непередаваемого значения (буквы, введенные для числа, плохо отформатированная дата и т.д.), мы должны вернуть undefined из анализатора. Это приведет к тому, что Angular удалит все уже установленные ключи $error и заменит весь объект только { "parse": true }. Больше парсеров не будет запущено. Модель не будет обновлена. Массив $parsers теперь должен использоваться только для синтаксического анализа.

Проверка

ngModelController имеет новое свойство $validators, которому мы можем назначить функции проверки. Они будут выполняться только в том случае, если конвейер синтаксического анализа был успешным. Возвращает false из одной из этих функций для значения, которое можно проанализировать как требуемый тип данных, но просто недействительно (строка слишком длинная, число вне диапазона и т.д.). Имя функции валидатора становится ключом проверки в объекте $error. Все валидаторы будут выполняться, даже если один из них возвращает false. Модель будет обновляться только в том случае, если проверка прошла успешно.

Это потенциально является нарушением изменений для существующих приложений, поскольку люди часто возвращают undefined из парсеров за недопустимое значение. Вот что я имел, что является типичным примером:

ctrl.$parsers.push(function (value) {
    if (!angular.isDefined(attrs.minNumber)) {
        return value;
    }
    var valid = angular.isUndefined(value) || Number(value) >= Number(attrs.minNumber);
    ctrl.$setValidity('minNumber', valid);
    return valid ? value : undefined;
});

В соответствии с этой новой схемой это должно быть перенесено на функцию проверки:

ctrl.$validators.minNumber = function (value) {
    return !value || !angular.isDefined(attrs.minNumber) || (value >= Number(attrs.minNumber));
});

Вот директива со всем исправленным:

angular.module('app', []).directive('number', function () {
    return {
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {

            // valid number
            ctrl.$parsers.push(function (value) {
                if(value === '') return value;
                return isFinite(value) ? Number(value) : undefined;
            });

            ctrl.$validators.minNumber = function (value) {
                return !value || !angular.isDefined(attrs.minNumber) || (value >= Number(attrs.minNumber));
            };

            ctrl.$validators.maxNumber = function (value) {
                return !value || !angular.isDefined(attrs.maxNumber) || (value <= Number(attrs.maxNumber));
            };
        }
    };
});

http://jsfiddle.net/snkesLv4/10/

Мне очень нравится этот новый способ - он намного чище.