Пользовательская директива 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", будет отображаться "Invalid per 'pattern'!". Я ожидал увидеть "Invalid per 'notpattern'!" когда вводится "abc", но это появляется только тогда, когда я ввожу "testRegExp", что указывает на то, что значение атрибута не оценивается.
Что я делаю неправильно?
Я знаю, что notPattern можно выполнить с помощью ngPattern с помощью чего-то вроде:
$scope.testRegExp = {
test: function (value) {
return !/^abc$/.test(value);
}
};
... но я хотел бы знать, почему пользовательская директива не оценивает выражение.
1 ответ
Оказывается, что ngPattern является особым случаем в Angular "входного атрибута с псевдонимом", что означает, что часы настроены для оценки выражения с помощью директивы с более высоким приоритетом. Функция прослушивателя watch просто устанавливает атрибут для оцененного результата каждый раз:
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/