Angularjs динамическая проверка ng-шаблона

84

У меня есть форма, которая, если флажок установлен в false, принудительно проверяет ввод текста с помощью директивы ng-required. Если флажок установлен в значение true, поле скрыто, а для параметра ng-required установлено значение false.

Проблема в том, что у меня также есть регулярное выражение для проверки, указанное на входе, а также с использованием угловой директивы ng-pattern. Проблема, с которой я сталкиваюсь, заключается в том, что если пользователь вводит недопустимый номер телефона, устанавливает флажок, чтобы отключить этот ввод (и, следовательно, не требует дополнительной проверки), форма не разрешит отправку, поскольку она недействительна на основе ng-шаблона.

Я попытался решить эту проблему, добавив функцию ng-change, чтобы установить модель ввода на null, однако ng-pattern и, следовательно, поле по-прежнему недействительны при первоначальном наборе флажка в false. Однако, если я сниму флажок, вернув все к исходной загрузке формы, а затем снова установите флажок, форма действительна и может быть отправлена. Я не уверен, что мне не хватает. Вот код ng-change, который у меня есть:

    var phoneNumberRegex = /^\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})$/;
    $scope.phoneNumberPattern = phoneNumberRegex;
    $scope.removeValidation = function() {
        if ($scope.cell._newUser === false) {
            $scope.request._number = '';
            $scope.phoneNumberPattern = /[0-9a-zA-Z]?/;
        } else {
            $scope.phoneNumberPattern = phoneNumberRegex;
        }
    };
Брайан
источник

Ответы:

175

Это интересная проблема, сложная проверка Angular. Следующая скрипка реализует то, что вы хотите:

http://jsfiddle.net/2G8gA/1/

Детали

Я создал новую директиву, rpatternкоторая представляет собой смесь Angular ng-requiredи ng-patternкода из input[type=text]. Что он делает, так это наблюдает за requiredатрибутом поля и учитывает это при проверке с помощью регулярного выражения, то есть, если это не требуется, отметьте поле какvalid-pattern .

Ноты

  • Большая часть кода написана на Angular и адаптирована к его потребностям.
  • Когда флажок установлен, поле является обязательным.
  • Поле не скрывается, если установленный флажок установлен в false.
  • Регулярное выражение упрощено для демонстрации (действительно 3 цифры).

Загрязнен (но меньше) решение, если вы не хотите , новую директиву, будет что - то вроде:

$scope.phoneNumberPattern = (function() {
    var regexp = /^\(?(\d{3})\)?[ .-]?(\d{3})[ .-]?(\d{4})$/;
    return {
        test: function(value) {
            if( $scope.requireTel === false ) {
                return true;
            }
            return regexp.test(value);
        }
    };
})();

А в HTML никаких изменений не потребуется:

<input type="text" ng-model="..." ng-required="requireTel"
    ng-pattern="phoneNumberPattern" />

Это фактически заставляет angular вызвать наш test() метод вместо того RegExp.test(), чтобы requiredучитывать.

Никос Параскевопулос
источник
2
Мне было бы очень интересно узнать, что делают круглые скобки вокруг функции и после нее. Без них не работает
NeedHack 03
5
Они вызывают функцию напрямую, фактически помещая ее возвращаемое значение в переменную. Это очень распространено в Javascript, чтобы не засорять внешнюю область видимости деталями реализации конкретного компонента, например, посмотрите на шаблон модуля .
Никос Параскевопулос
6
Грязное решение - подшутить над AngularJS на основе «утиного ввода» JS - это самый потрясающий код, который я видел сегодня. Действительно умное решение!
Флориан Лох
Спасибо за отличный код, но все еще не очень понятный, 1) согласно docs.angularjs.org/api/ng/directive/input : «Если выражение оценивается как объект RegExp, то это используется напрямую. Если выражение оценивает в строку, тогда он будет преобразован в RegExp », но я полагаю, что при возврате phoneNumberPattern является объектом? Это должен быть объект Regxp? 2) А в хранилище функции (значение) {} в тесте, откуда берется параметр "значение"? Благодарю за любые ответы!
user2499325
1
1) Предложение «Если выражение оценивается как RegExp» реализуется Angular путем проверки того, есть ли у полученной вещи testметод. Вот почему мы даем ему объект с нашим собственным заказом test(), по сути имитирующий собственный JS RegExp. 2) valueКонечно, Angular передает его при выполнении фактической проверки действительности.
Никос Параскевопулос,
25

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

<form name="telForm">
  <input name="cb" type='checkbox' data-ng-modal='requireTel'>
  <input name="tel" type="text" ng-model="..." ng-if='requireTel' ng-pattern="phoneNumberPattern" required/>
  <button type="submit" ng-disabled="telForm.$invalid || telForm.$pristine">Submit</button>
</form>

Обратите внимание на второй ввод: мы можем использовать ng-ifдля управления отрисовкой и проверкой в ​​формах. Если requireTelпеременная не установлена, второй вход будет не только скрыт, но и не отображен вообще, поэтому форма пройдет проверку, кнопка станет активной, и вы получите то, что вам нужно.

кумархарш
источник
1
Плюс в том, что это просто. Обратной стороной является то, что любые входные данные, которые удаляются, когда выражение ng-if ложно, будут иметь любой текст в них удален, если позже ng-if будет оценено как истинное. Тем не менее, +1 для простоты.
Brad
Я хотел добавить, что если вы пойдете по этому пути, убедитесь, что вы понимаете, что все в ng-if (если вы, например, поместите его в div) теперь будет иметь свою собственную область видимости.
Брэд
5

Используемый узор:

 ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"

Используемый справочный файл:

 '<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>'

Пример ввода:

 <input type="number" require ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"><input type="submit">
Анил Сингх
источник
2

 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>
<input type="number" require ng-pattern="/^\d{0,9}(\.\d{1,9})?$/"><input type="submit">

Джихо Паулозе
источник
2

Я только что столкнулся с этим на днях.

Что я сделал, что кажется проще, чем описанное выше, - это установить шаблон для переменной в области видимости и сослаться на него в ng-pattern в представлении.

Когда «флажок снят», я просто устанавливаю значение регулярного выражения на /.*/ в обратном вызове onChanged (если не будет отмечен). ng-pattern выбирает, который меняется и говорит: «Хорошо, ваше значение в порядке». Форма теперь действительна. Я бы также удалил неверные данные из поля, чтобы # у вас не было явно плохого телефона.

У меня были дополнительные проблемы с ng-required, и я сделал то же самое. Работал как шарм.

Джессевулф
источник
0

Устанавливает ключ ошибки проверки шаблона, если ngModel $ viewValue не соответствует RegExp, найденному путем оценки выражения Angular, указанного в значении атрибута. Если выражение оценивается как объект RegExp, то он используется напрямую. Если выражение оценивается как строка, оно будет преобразовано в RegExp после помещения его в символы ^ и $.

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

Пример из Angular docs мне подходит:

Изменение встроенных валидаторов

html

<form name="form" class="css-form" novalidate>
  <div>
   Overwritten Email:
   <input type="email" ng-model="myEmail" overwrite-email name="overwrittenEmail" />
   <span ng-show="form.overwrittenEmail.$error.email">This email format is invalid!</span><br>
   Model: {{myEmail}}
  </div>
</form>

js

var app = angular.module('form-example-modify-validators', []);

app.directive('overwriteEmail', function() {
    var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@example\.com$/i;

    return {
        require: 'ngModel',
        restrict: '',
        link: function(scope, elm, attrs, ctrl) {
            // only apply the validator if ngModel is present and Angular has added the email validator
            if (ctrl && ctrl.$validators.email) {

                // this will overwrite the default Angular email validator
                ctrl.$validators.email = function(modelValue) {
                    return ctrl.$isEmpty(modelValue) || EMAIL_REGEXP.test(modelValue);
                };
             }
         }
     };
 });

Plunker

Теодор
источник
-1

Вы можете использовать сайт https://regex101.com/ для создания своего собственного шаблона для какой-либо страны:

Например, Польша:

-pattern = xxxxxxxxx OR xxx-xxx-xxx OR xxx xxx xxx 
-regexp ="^\d{9}|^\d{3}-\d{3}-\d{3}|^\d{3}\s\d{3}\s\d{3}"
Лептон
источник