С помощью Angular директив проверки с Breeze блокирует любой ввод, который недействителен

Если вы добавите какую-либо из директив angular для проверки (ng-minlength, ng-maxlength, ng-pattern и т.д.) на вход, привязанный к ветру, он блокирует любой пользовательский ввод, если он найден недействителен.

Если значение из ng-model изначально корректно, оно отображается, но если вы измените значение на что-то недействительное, поле ввода будет очищено, то для модели будет установлено значение null, и вы не сможете ввести все, что может быть изначально инвалид. Однако, если вы скопируете действительное значение в поле, которое оно показывает.

Мне было бы хорошо, если значение модели было установлено равным null, если оно недействительно, если оно не очистило вход, а затем предотвратило изменения.

Также у меня возникает ощущение, что все, что вызывает эту проблему, также испортит u-mask. То же самое происходит и без директив angular.

вот Plunker, который я нашел по аналогичному вопросу, который я изменил, чтобы показать свою проблему: http://plnkr.co/edit/dVsF7GFY65a30soLL5W8?p=preview


Edit

После многих часов исследований я нашел решение, которое работает, хотя я не уверен в каких-либо побочных эффектах.

Это связано с тем, как angular выполняет валидацию в первую очередь, устанавливая значение $modelValue в 'undefined', если он не удаляет какие-либо валидаторы, поскольку он делает это через $parsers и $formatters.

Я нашел этот код в angular (строка 16331), который вызывается каждым валидатором angular:

function validate(ctrl, validatorName, validity, value){
  ctrl.$setValidity(validatorName, validity);
  return validity ? value : undefined;
}

Я изменил его, чтобы вернуть 'значение' вместо 'undefined':

function validate(ctrl, validatorName, validity, value){
      ctrl.$setValidity(validatorName, validity);

      return value;
    }

Angular все еще корректно устанавливает правильность. Хотя я уверен, что это не лучшее решение или даже хорошее.

Я подозреваю, что проблема возникает, когда angular устанавливает $modelValue в 'undefined', тогда Breeze видит, что модель изменилась и обновляет объект, который затем обновляет модель, которая затем очищает ввод и т.д.... Или что-то вроде этого...

Я нашел, что это полезно в моих поисках. Возможно, это будет полезно для одного из вас, который знает гораздо больше, чем я https://github.com/angular/angular.js/issues/1412

Ответ 1

Angular 1.3.0-rc.1 представил параметр allowInvalid для использования с директивой ngModelOptions. Это, по сути, формализация взлома OP в строке 16331. Опция сообщает Angular разрешить ввод недопустимых входных данных формы в область $scope и решает проблему аккуратно.

Использование:

<input type="email" ng-model-options="{allowInvalid: true}" ng-model="my_breeze_model.email"/>

См. этот запрос функции для получения дополнительной информации: https://github.com/angular/angular.js/issues/8290.

Ответ 2

Я рад посмотреть на ваш плункер и посмотреть, есть ли что-то, что может сделать Бриз.

Я не очень удивлен. Ng также борется, когда вы совмещаете его с проверкой HTML 5, насколько я помню. Вы действительно должны использовать только одну схему, я думаю.

Вы не согласны?

Кроме того, рассмотрели ли вы директиву zValidate в Breeze Labs breeze.directives.js? Мы считаем, что это лучший способ разоблачить ошибки проверки подлинности объекта Breeze в представлении.

Ответ 3

Еще одно решение - использовать атрибут ng-model-options, доступный с помощью Angular 1.3 +.

Таким образом, вы можете предотвратить дайджест Angular, возникающий после каждого нажатия клавиши, и вместо этого отложить его, например, на событие "размытие", чтобы у использования была возможность фактически ввести действительные данные.

Это будет выглядеть так:

<input type="email" ng-model="customer.email" ng-model-options="{ updateOn: 'blur' }">

Тем не менее, это все еще имеет ограничение на то, что если вы введете недопустимый ввод, при размытии вход будет очищен, и использование снова должно будет ввести его снова. На мой взгляд, это не очень удобно для пользователя, поэтому я буду пытаться использовать только один ветерок, чтобы обойти эту проблему.

Однако, я думал, что это решение также стоит упомянуть здесь.

Ответ 4

https://docs.angularjs.org/error/ngModel/numfmt описывает, как Angular считает ошибку программирования, а не ошибкой ввода пользователя, если изменения в программной модели не уважают правила проверки ввода.

Если ваша модель не содержит фактических номеров, то разработчик приложения может использовать директиву, которая будет выполнять преобразование в конвейере ngModel $formatters и $parsers.

В их примере описывается значение модели String для <input type='number'>, но, я думаю, здесь применяется одна и та же логика. Если ваш вход содержит атрибут minLength, область не должна обновляться с слишком короткими строками.

Итак, чтобы исправить это, добавьте в свой файл настраиваемую директиву, которая подталкивает пользовательский парсер в конвейер $parsers.

Например, следующая директива не будет записывать значение <input type='text' minLength='4' min4> в область действия до тех пор, пока в нее не будет введена достаточно длинная строка:

.directive('min4', function() {
    return {
      require: 'ngModel',
      link: function(scope, element, attrs, ngModel) {
        ngModel.$parsers.push(function(value) {
          return value && value.length >= 4 ? value : "";
        });
      }
    };
  });

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

См. Демо-версия Plunker