Пользовательская директива notPattern похожа на ngPattern, но проверяет, не соответствует ли RegExp

Я пытаюсь написать пользовательскую директиву AngularJS, аналогичную ngPattern, за исключением того, что эта директива не пройдет проверку, если RegExp не соответствует.

Следование источнику ngPattern, я придумал:

  .directive("notPattern", function () {
    return {
      restrict: "A",
      require: "?ngModel",
      link: function (scope, elem, attr, ctrl) {
        if (!ctrl) return;

        var regExp, notPatternExp = attr.notPattern;
        attr.$observe("notPattern", function (regex) {
          if (angular.isString(regex) && regex.length > 0) {
            regex = new RegExp("^" + regex + "$");
          }

          if (regex && !regex.test) {
            var elemClone = angular.element(elem).clone();
            var elemHtml = angular.element("<div>").append(elemClone).html();
            throw new Error("Expected " + notPatternExp + " to be a RegExp but was " + regex + ". Element: " + elemHtml);
          }

          regExp = regex || undefined;
          ctrl.$validate();
        });

        ctrl.$validators.notpattern = function (value) {
          return ctrl.$isEmpty(value) || angular.isUndefined(regExp) || !regExp.test(value);
        };
      }
    };
  })

Это работает, когда я указываю источник регулярного выражения в атрибуте, но я хочу разрешить прямое использование объекта RegExp, например ngPattern.

Проблема в том, что выражение не оценивается.

Вот пример JSFiddle:
http://jsfiddle.net/8Lk3pqep/1/

В этом примере при вводе в текстовое поле чего-либо, кроме «abc», будет показано «Недопустимо для «шаблона»!». Я ожидал увидеть «Неверно для« не шаблона »!» когда вводится «abc», но это появляется только тогда, когда я ввожу «testRegExp», что указывает на то, что значение атрибута не оценивается.

Что я делаю неправильно?

Я знаю, что notPattern можно выполнить с помощью ngPattern с помощью чего-то вроде:

$scope.testRegExp = {
  test: function (value) {
    return !/^abc$/.test(value);
  }
};

.. но я хотел бы знать, почему пользовательская директива не оценивает выражение.


person Daniel Trebbien    schedule 12.06.2015    source источник


Ответы (1)


Оказывается, ngPattern — это особый случай в Angular «атрибута ввода с псевдонимом», что означает, что часы настроены для оценки выражения с помощью директивы с более высоким приоритетом. Функция наблюдателя каждый раз просто устанавливает атрибут для оцененного результата:
https://github.com/angular/angular.js/blob/bfcf9946e16d21b55dde50d4d21c71c898b10215/src/ng/directive/attrs.js#L377

Чтобы исправить директиву notPattern, вместо наблюдения за атрибутом notPattern настройте отслеживание выражения notPattern, чтобы отразить встроенную настройку для атрибута ngPattern:

  .directive("notPattern", function () {
    return {
      restrict: "A",
      require: "?ngModel",
      link: function (scope, elem, attr, ctrl) {
        if (!ctrl) return;

        var regExp, notPatternExp = attr.notPattern;
        scope.$watch(notPatternExp, function (regex) {
          if (angular.isString(regex) && regex.length > 0) {
            regex = new RegExp("^" + regex + "$");
          }

          if (regex && !regex.test) {
            var elemClone = angular.element(elem).clone();
            var elemHtml = angular.element("<div>").append(elemClone).html();
            throw new Error("Expected " + notPatternExp + " to be a RegExp but was " + regex + ". Element: " + elemHtml);
          }

          regExp = regex || undefined;
          ctrl.$validate();
        });

        ctrl.$validators.notpattern = function (value) {
          return ctrl.$isEmpty(value) || angular.isUndefined(regExp) || !regExp.test(value);
        };
      }
    };
  })

Вот обновленный JSFiddle:
http://jsfiddle.net/8Lk3pqep/2/

person Daniel Trebbien    schedule 17.06.2015