U4-8445 Validation on the Email field for Members will not allow the entry of root domains greater than four characters.
This commit is contained in:
@@ -1,28 +1,28 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valHighlight
|
||||
* @restrict A
|
||||
* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second
|
||||
**/
|
||||
function valHighlight($timeout) {
|
||||
return {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
|
||||
attrs.$observe("valHighlight", function (newVal) {
|
||||
if (newVal === "true") {
|
||||
element.addClass("highlight-error");
|
||||
$timeout(function () {
|
||||
//set the bound scope property to false
|
||||
scope[attrs.valHighlight] = false;
|
||||
}, 1000);
|
||||
}
|
||||
else {
|
||||
element.removeClass("highlight-error");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valHighlight", valHighlight);
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valHighlight
|
||||
* @restrict A
|
||||
* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second
|
||||
**/
|
||||
function valHighlight($timeout) {
|
||||
return {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
|
||||
attrs.$observe("valHighlight", function (newVal) {
|
||||
if (newVal === "true") {
|
||||
element.addClass("highlight-error");
|
||||
$timeout(function () {
|
||||
//set the bound scope property to false
|
||||
scope[attrs.valHighlight] = false;
|
||||
}, 1000);
|
||||
}
|
||||
else {
|
||||
element.removeClass("highlight-error");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valHighlight", valHighlight);
|
||||
@@ -1,24 +1,24 @@
|
||||
angular.module('umbraco.directives.validation')
|
||||
.directive('valCompare',function () {
|
||||
return {
|
||||
require: "ngModel",
|
||||
link: function (scope, elem, attrs, ctrl) {
|
||||
|
||||
//TODO: Pretty sure this should be done using a requires ^form in the directive declaration
|
||||
var otherInput = elem.inheritedData("$formController")[attrs.valCompare];
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
if(value === otherInput.$viewValue) {
|
||||
ctrl.$setValidity("valCompare", true);
|
||||
return value;
|
||||
}
|
||||
ctrl.$setValidity("valCompare", false);
|
||||
});
|
||||
|
||||
otherInput.$parsers.push(function(value) {
|
||||
ctrl.$setValidity("valCompare", value === ctrl.$viewValue);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
};
|
||||
angular.module('umbraco.directives.validation')
|
||||
.directive('valCompare',function () {
|
||||
return {
|
||||
require: "ngModel",
|
||||
link: function (scope, elem, attrs, ctrl) {
|
||||
|
||||
//TODO: Pretty sure this should be done using a requires ^form in the directive declaration
|
||||
var otherInput = elem.inheritedData("$formController")[attrs.valCompare];
|
||||
|
||||
ctrl.$parsers.push(function(value) {
|
||||
if(value === otherInput.$viewValue) {
|
||||
ctrl.$setValidity("valCompare", true);
|
||||
return value;
|
||||
}
|
||||
ctrl.$setValidity("valCompare", false);
|
||||
});
|
||||
|
||||
otherInput.$parsers.push(function(value) {
|
||||
ctrl.$setValidity("valCompare", value === ctrl.$viewValue);
|
||||
return value;
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -29,6 +29,12 @@ function valEmail(valEmailExpression) {
|
||||
}
|
||||
};
|
||||
|
||||
//we need to remove the existing parsers = the default angular one which is created by
|
||||
// type="email", but this has a regex issue, so we'll remove that and add our custom one
|
||||
ctrl.$parsers.pop();
|
||||
//we also need to remove the existing formatter - the default angular one will not render
|
||||
// what it thinks is an invalid email address, so it will just be blank
|
||||
ctrl.$formatters.pop();
|
||||
ctrl.$parsers.push(patternValidator);
|
||||
}
|
||||
};
|
||||
@@ -36,7 +42,8 @@ function valEmail(valEmailExpression) {
|
||||
|
||||
angular.module('umbraco.directives.validation')
|
||||
.directive("valEmail", valEmail)
|
||||
.factory('valEmailExpression', function() {
|
||||
.factory('valEmailExpression', function () {
|
||||
//NOTE: This is the fixed regex which is part of the newer angular
|
||||
return {
|
||||
EMAIL_REGEXP: /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i
|
||||
};
|
||||
@@ -1,133 +1,133 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valFormManager
|
||||
* @restrict A
|
||||
* @require formController
|
||||
* @description Used to broadcast an event to all elements inside this one to notify that form validation has
|
||||
* changed. If we don't use this that means you have to put a watch for each directive on a form's validation
|
||||
* changing which would result in much higher processing. We need to actually watch the whole $error collection of a form
|
||||
* because just watching $valid or $invalid doesn't acurrately trigger form validation changing.
|
||||
* This also sets the show-validation (or a custom) css class on the element when the form is invalid - this lets
|
||||
* us css target elements to be displayed when the form is submitting/submitted.
|
||||
* Another thing this directive does is to ensure that any .control-group that contains form elements that are invalid will
|
||||
* be marked with the 'error' css class. This ensures that labels included in that control group are styled correctly.
|
||||
**/
|
||||
function valFormManager(serverValidationManager, $rootScope, $log, $timeout, notificationsService, eventsService, $routeParams) {
|
||||
return {
|
||||
require: "form",
|
||||
restrict: "A",
|
||||
controller: function($scope) {
|
||||
//This exposes an API for direct use with this directive
|
||||
|
||||
var unsubscribe = [];
|
||||
var self = this;
|
||||
|
||||
//This is basically the same as a directive subscribing to an event but maybe a little
|
||||
// nicer since the other directive can use this directive's API instead of a magical event
|
||||
this.onValidationStatusChanged = function (cb) {
|
||||
unsubscribe.push($scope.$on("valStatusChanged", function(evt, args) {
|
||||
cb.apply(self, [evt, args]);
|
||||
}));
|
||||
};
|
||||
|
||||
//Ensure to remove the event handlers when this instance is destroyted
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
},
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
scope.$watch(function () {
|
||||
return formCtrl.$error;
|
||||
}, function (e) {
|
||||
scope.$broadcast("valStatusChanged", { form: formCtrl });
|
||||
|
||||
//find all invalid elements' .control-group's and apply the error class
|
||||
var inError = element.find(".control-group .ng-invalid").closest(".control-group");
|
||||
inError.addClass("error");
|
||||
|
||||
//find all control group's that have no error and ensure the class is removed
|
||||
var noInError = element.find(".control-group .ng-valid").closest(".control-group").not(inError);
|
||||
noInError.removeClass("error");
|
||||
|
||||
}, true);
|
||||
|
||||
var className = attr.valShowValidation ? attr.valShowValidation : "show-validation";
|
||||
var savingEventName = attr.savingEvent ? attr.savingEvent : "formSubmitting";
|
||||
var savedEvent = attr.savedEvent ? attr.savingEvent : "formSubmitted";
|
||||
|
||||
//This tracks if the user is currently saving a new item, we use this to determine
|
||||
// if we should display the warning dialog that they are leaving the page - if a new item
|
||||
// is being saved we never want to display that dialog, this will also cause problems when there
|
||||
// are server side validation issues.
|
||||
var isSavingNewItem = false;
|
||||
|
||||
//we should show validation if there are any msgs in the server validation collection
|
||||
if (serverValidationManager.items.length > 0) {
|
||||
element.addClass(className);
|
||||
}
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the forms saving event
|
||||
unsubscribe.push(scope.$on(savingEventName, function(ev, args) {
|
||||
element.addClass(className);
|
||||
|
||||
//set the flag so we can check to see if we should display the error.
|
||||
isSavingNewItem = $routeParams.create;
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
unsubscribe.push(scope.$on(savedEvent, function(ev, args) {
|
||||
//remove validation class
|
||||
element.removeClass(className);
|
||||
|
||||
//clear form state as at this point we retrieve new data from the server
|
||||
//and all validation will have cleared at this point
|
||||
formCtrl.$setPristine();
|
||||
}));
|
||||
|
||||
//This handles the 'unsaved changes' dialog which is triggered when a route is attempting to be changed but
|
||||
// the form has pending changes
|
||||
var locationEvent = $rootScope.$on('$locationChangeStart', function(event, nextLocation, currentLocation) {
|
||||
if (!formCtrl.$dirty || isSavingNewItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
var path = nextLocation.split("#")[1];
|
||||
if (path) {
|
||||
if (path.indexOf("%253") || path.indexOf("%252")) {
|
||||
path = decodeURIComponent(path);
|
||||
}
|
||||
|
||||
if (!notificationsService.hasView()) {
|
||||
var msg = { view: "confirmroutechange", args: { path: path, listener: locationEvent } };
|
||||
notificationsService.add(msg);
|
||||
}
|
||||
|
||||
//prevent the route!
|
||||
event.preventDefault();
|
||||
|
||||
//raise an event
|
||||
eventsService.emit("valFormManager.pendingChanges", true);
|
||||
}
|
||||
|
||||
});
|
||||
unsubscribe.push(locationEvent);
|
||||
|
||||
//Ensure to remove the event handler when this instance is destroyted
|
||||
scope.$on('$destroy', function() {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
$timeout(function(){
|
||||
formCtrl.$setPristine();
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valFormManager
|
||||
* @restrict A
|
||||
* @require formController
|
||||
* @description Used to broadcast an event to all elements inside this one to notify that form validation has
|
||||
* changed. If we don't use this that means you have to put a watch for each directive on a form's validation
|
||||
* changing which would result in much higher processing. We need to actually watch the whole $error collection of a form
|
||||
* because just watching $valid or $invalid doesn't acurrately trigger form validation changing.
|
||||
* This also sets the show-validation (or a custom) css class on the element when the form is invalid - this lets
|
||||
* us css target elements to be displayed when the form is submitting/submitted.
|
||||
* Another thing this directive does is to ensure that any .control-group that contains form elements that are invalid will
|
||||
* be marked with the 'error' css class. This ensures that labels included in that control group are styled correctly.
|
||||
**/
|
||||
function valFormManager(serverValidationManager, $rootScope, $log, $timeout, notificationsService, eventsService, $routeParams) {
|
||||
return {
|
||||
require: "form",
|
||||
restrict: "A",
|
||||
controller: function($scope) {
|
||||
//This exposes an API for direct use with this directive
|
||||
|
||||
var unsubscribe = [];
|
||||
var self = this;
|
||||
|
||||
//This is basically the same as a directive subscribing to an event but maybe a little
|
||||
// nicer since the other directive can use this directive's API instead of a magical event
|
||||
this.onValidationStatusChanged = function (cb) {
|
||||
unsubscribe.push($scope.$on("valStatusChanged", function(evt, args) {
|
||||
cb.apply(self, [evt, args]);
|
||||
}));
|
||||
};
|
||||
|
||||
//Ensure to remove the event handlers when this instance is destroyted
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
},
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
scope.$watch(function () {
|
||||
return formCtrl.$error;
|
||||
}, function (e) {
|
||||
scope.$broadcast("valStatusChanged", { form: formCtrl });
|
||||
|
||||
//find all invalid elements' .control-group's and apply the error class
|
||||
var inError = element.find(".control-group .ng-invalid").closest(".control-group");
|
||||
inError.addClass("error");
|
||||
|
||||
//find all control group's that have no error and ensure the class is removed
|
||||
var noInError = element.find(".control-group .ng-valid").closest(".control-group").not(inError);
|
||||
noInError.removeClass("error");
|
||||
|
||||
}, true);
|
||||
|
||||
var className = attr.valShowValidation ? attr.valShowValidation : "show-validation";
|
||||
var savingEventName = attr.savingEvent ? attr.savingEvent : "formSubmitting";
|
||||
var savedEvent = attr.savedEvent ? attr.savingEvent : "formSubmitted";
|
||||
|
||||
//This tracks if the user is currently saving a new item, we use this to determine
|
||||
// if we should display the warning dialog that they are leaving the page - if a new item
|
||||
// is being saved we never want to display that dialog, this will also cause problems when there
|
||||
// are server side validation issues.
|
||||
var isSavingNewItem = false;
|
||||
|
||||
//we should show validation if there are any msgs in the server validation collection
|
||||
if (serverValidationManager.items.length > 0) {
|
||||
element.addClass(className);
|
||||
}
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the forms saving event
|
||||
unsubscribe.push(scope.$on(savingEventName, function(ev, args) {
|
||||
element.addClass(className);
|
||||
|
||||
//set the flag so we can check to see if we should display the error.
|
||||
isSavingNewItem = $routeParams.create;
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
unsubscribe.push(scope.$on(savedEvent, function(ev, args) {
|
||||
//remove validation class
|
||||
element.removeClass(className);
|
||||
|
||||
//clear form state as at this point we retrieve new data from the server
|
||||
//and all validation will have cleared at this point
|
||||
formCtrl.$setPristine();
|
||||
}));
|
||||
|
||||
//This handles the 'unsaved changes' dialog which is triggered when a route is attempting to be changed but
|
||||
// the form has pending changes
|
||||
var locationEvent = $rootScope.$on('$locationChangeStart', function(event, nextLocation, currentLocation) {
|
||||
if (!formCtrl.$dirty || isSavingNewItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
var path = nextLocation.split("#")[1];
|
||||
if (path) {
|
||||
if (path.indexOf("%253") || path.indexOf("%252")) {
|
||||
path = decodeURIComponent(path);
|
||||
}
|
||||
|
||||
if (!notificationsService.hasView()) {
|
||||
var msg = { view: "confirmroutechange", args: { path: path, listener: locationEvent } };
|
||||
notificationsService.add(msg);
|
||||
}
|
||||
|
||||
//prevent the route!
|
||||
event.preventDefault();
|
||||
|
||||
//raise an event
|
||||
eventsService.emit("valFormManager.pendingChanges", true);
|
||||
}
|
||||
|
||||
});
|
||||
unsubscribe.push(locationEvent);
|
||||
|
||||
//Ensure to remove the event handler when this instance is destroyted
|
||||
scope.$on('$destroy', function() {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
$timeout(function(){
|
||||
formCtrl.$setPristine();
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valFormManager", valFormManager);
|
||||
@@ -1,196 +1,196 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valPropertyMsg
|
||||
* @restrict A
|
||||
* @element textarea
|
||||
* @requires formController
|
||||
* @description This directive is used to control the display of the property level validation message.
|
||||
* We will listen for server side validation changes
|
||||
* and when an error is detected for this property we'll show the error message.
|
||||
* In order for this directive to work, the valStatusChanged directive must be placed on the containing form.
|
||||
**/
|
||||
function valPropertyMsg(serverValidationManager) {
|
||||
|
||||
return {
|
||||
scope: {
|
||||
property: "="
|
||||
},
|
||||
require: "^form", //require that this directive is contained within an ngForm
|
||||
replace: true, //replace the element with the template
|
||||
restrict: "E", //restrict to element
|
||||
template: "<div ng-show=\"errorMsg != ''\" class='alert alert-error property-error' >{{errorMsg}}</div>",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller
|
||||
which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attrs, formCtrl) {
|
||||
|
||||
var watcher = null;
|
||||
|
||||
// Gets the error message to display
|
||||
function getErrorMsg() {
|
||||
//this can be null if no property was assigned
|
||||
if (scope.property) {
|
||||
//first try to get the error msg from the server collection
|
||||
var err = serverValidationManager.getPropertyError(scope.property.alias, "");
|
||||
//if there's an error message use it
|
||||
if (err && err.errorMsg) {
|
||||
return err.errorMsg;
|
||||
}
|
||||
else {
|
||||
return scope.property.propertyErrorMessage ? scope.property.propertyErrorMessage : "Property has errors";
|
||||
}
|
||||
|
||||
}
|
||||
return "Property has errors";
|
||||
}
|
||||
|
||||
// We need to subscribe to any changes to our model (based on user input)
|
||||
// This is required because when we have a server error we actually invalidate
|
||||
// the form which means it cannot be resubmitted.
|
||||
// So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
function startWatch() {
|
||||
//if there's not already a watch
|
||||
if (!watcher) {
|
||||
watcher = scope.$watch("property.value", function (newValue, oldValue) {
|
||||
|
||||
if (!newValue || angular.equals(newValue, oldValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var errCount = 0;
|
||||
for (var e in formCtrl.$error) {
|
||||
if (angular.isArray(formCtrl.$error[e])) {
|
||||
errCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//we are explicitly checking for valServer errors here, since we shouldn't auto clear
|
||||
// based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg
|
||||
// is the only one, then we'll clear.
|
||||
|
||||
if ((errCount === 1 && angular.isArray(formCtrl.$error.valPropertyMsg)) || (formCtrl.$invalid && angular.isArray(formCtrl.$error.valServer))) {
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
stopWatch();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
//clear the watch when the property validator is valid again
|
||||
function stopWatch() {
|
||||
if (watcher) {
|
||||
watcher();
|
||||
watcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
var hasError = false;
|
||||
|
||||
//create properties on our custom scope so we can use it in our template
|
||||
scope.errorMsg = "";
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for form error changes
|
||||
unsubscribe.push(scope.$on("valStatusChanged", function(evt, args) {
|
||||
if (args.form.$invalid) {
|
||||
|
||||
//first we need to check if the valPropertyMsg validity is invalid
|
||||
if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) {
|
||||
//since we already have an error we'll just return since this means we've already set the
|
||||
// hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe
|
||||
return;
|
||||
}
|
||||
else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) {
|
||||
//check if it's one of the properties that is invalid in the current content property
|
||||
hasError = true;
|
||||
//update the validation message if we don't already have one assigned.
|
||||
if (showValidation && scope.errorMsg === "") {
|
||||
scope.errorMsg = getErrorMsg();
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}, true));
|
||||
|
||||
//listen for the forms saving event
|
||||
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (hasError && scope.errorMsg === "") {
|
||||
scope.errorMsg = getErrorMsg();
|
||||
}
|
||||
else if (!hasError) {
|
||||
scope.errorMsg = "";
|
||||
stopWatch();
|
||||
}
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
|
||||
showValidation = false;
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
stopWatch();
|
||||
}));
|
||||
|
||||
//listen for server validation changes
|
||||
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
|
||||
// validation changes to fields in the property this is because some server side validators may not
|
||||
// return the field name for which the error belongs too, just the property for which it belongs.
|
||||
// It's important to note that we need to subscribe to server validation changes here because we always must
|
||||
// indicate that a content property is invalid at the property level since developers may not actually implement
|
||||
// the correct field validation in their property editors.
|
||||
|
||||
if (scope.property) { //this can be null if no property was assigned
|
||||
serverValidationManager.subscribe(scope.property.alias, "", function (isValid, propertyErrors, allErrors) {
|
||||
hasError = !isValid;
|
||||
if (hasError) {
|
||||
//set the error message to the server message
|
||||
scope.errorMsg = propertyErrors[0].errorMsg;
|
||||
//flag that the current validator is invalid
|
||||
formCtrl.$setValidity('valPropertyMsg', false);
|
||||
startWatch();
|
||||
}
|
||||
else {
|
||||
scope.errorMsg = "";
|
||||
//flag that the current validator is valid
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
stopWatch();
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
stopWatch();
|
||||
serverValidationManager.unsubscribe(scope.property.alias, "");
|
||||
});
|
||||
}
|
||||
|
||||
//when the scope is disposed we need to unsubscribe
|
||||
scope.$on('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valPropertyMsg
|
||||
* @restrict A
|
||||
* @element textarea
|
||||
* @requires formController
|
||||
* @description This directive is used to control the display of the property level validation message.
|
||||
* We will listen for server side validation changes
|
||||
* and when an error is detected for this property we'll show the error message.
|
||||
* In order for this directive to work, the valStatusChanged directive must be placed on the containing form.
|
||||
**/
|
||||
function valPropertyMsg(serverValidationManager) {
|
||||
|
||||
return {
|
||||
scope: {
|
||||
property: "="
|
||||
},
|
||||
require: "^form", //require that this directive is contained within an ngForm
|
||||
replace: true, //replace the element with the template
|
||||
restrict: "E", //restrict to element
|
||||
template: "<div ng-show=\"errorMsg != ''\" class='alert alert-error property-error' >{{errorMsg}}</div>",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller
|
||||
which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attrs, formCtrl) {
|
||||
|
||||
var watcher = null;
|
||||
|
||||
// Gets the error message to display
|
||||
function getErrorMsg() {
|
||||
//this can be null if no property was assigned
|
||||
if (scope.property) {
|
||||
//first try to get the error msg from the server collection
|
||||
var err = serverValidationManager.getPropertyError(scope.property.alias, "");
|
||||
//if there's an error message use it
|
||||
if (err && err.errorMsg) {
|
||||
return err.errorMsg;
|
||||
}
|
||||
else {
|
||||
return scope.property.propertyErrorMessage ? scope.property.propertyErrorMessage : "Property has errors";
|
||||
}
|
||||
|
||||
}
|
||||
return "Property has errors";
|
||||
}
|
||||
|
||||
// We need to subscribe to any changes to our model (based on user input)
|
||||
// This is required because when we have a server error we actually invalidate
|
||||
// the form which means it cannot be resubmitted.
|
||||
// So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
function startWatch() {
|
||||
//if there's not already a watch
|
||||
if (!watcher) {
|
||||
watcher = scope.$watch("property.value", function (newValue, oldValue) {
|
||||
|
||||
if (!newValue || angular.equals(newValue, oldValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var errCount = 0;
|
||||
for (var e in formCtrl.$error) {
|
||||
if (angular.isArray(formCtrl.$error[e])) {
|
||||
errCount++;
|
||||
}
|
||||
}
|
||||
|
||||
//we are explicitly checking for valServer errors here, since we shouldn't auto clear
|
||||
// based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg
|
||||
// is the only one, then we'll clear.
|
||||
|
||||
if ((errCount === 1 && angular.isArray(formCtrl.$error.valPropertyMsg)) || (formCtrl.$invalid && angular.isArray(formCtrl.$error.valServer))) {
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
stopWatch();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
//clear the watch when the property validator is valid again
|
||||
function stopWatch() {
|
||||
if (watcher) {
|
||||
watcher();
|
||||
watcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
var hasError = false;
|
||||
|
||||
//create properties on our custom scope so we can use it in our template
|
||||
scope.errorMsg = "";
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for form error changes
|
||||
unsubscribe.push(scope.$on("valStatusChanged", function(evt, args) {
|
||||
if (args.form.$invalid) {
|
||||
|
||||
//first we need to check if the valPropertyMsg validity is invalid
|
||||
if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) {
|
||||
//since we already have an error we'll just return since this means we've already set the
|
||||
// hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe
|
||||
return;
|
||||
}
|
||||
else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) {
|
||||
//check if it's one of the properties that is invalid in the current content property
|
||||
hasError = true;
|
||||
//update the validation message if we don't already have one assigned.
|
||||
if (showValidation && scope.errorMsg === "") {
|
||||
scope.errorMsg = getErrorMsg();
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasError = false;
|
||||
scope.errorMsg = "";
|
||||
}
|
||||
}, true));
|
||||
|
||||
//listen for the forms saving event
|
||||
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (hasError && scope.errorMsg === "") {
|
||||
scope.errorMsg = getErrorMsg();
|
||||
}
|
||||
else if (!hasError) {
|
||||
scope.errorMsg = "";
|
||||
stopWatch();
|
||||
}
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
|
||||
showValidation = false;
|
||||
scope.errorMsg = "";
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
stopWatch();
|
||||
}));
|
||||
|
||||
//listen for server validation changes
|
||||
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
|
||||
// validation changes to fields in the property this is because some server side validators may not
|
||||
// return the field name for which the error belongs too, just the property for which it belongs.
|
||||
// It's important to note that we need to subscribe to server validation changes here because we always must
|
||||
// indicate that a content property is invalid at the property level since developers may not actually implement
|
||||
// the correct field validation in their property editors.
|
||||
|
||||
if (scope.property) { //this can be null if no property was assigned
|
||||
serverValidationManager.subscribe(scope.property.alias, "", function (isValid, propertyErrors, allErrors) {
|
||||
hasError = !isValid;
|
||||
if (hasError) {
|
||||
//set the error message to the server message
|
||||
scope.errorMsg = propertyErrors[0].errorMsg;
|
||||
//flag that the current validator is invalid
|
||||
formCtrl.$setValidity('valPropertyMsg', false);
|
||||
startWatch();
|
||||
}
|
||||
else {
|
||||
scope.errorMsg = "";
|
||||
//flag that the current validator is valid
|
||||
formCtrl.$setValidity('valPropertyMsg', true);
|
||||
stopWatch();
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
stopWatch();
|
||||
serverValidationManager.unsubscribe(scope.property.alias, "");
|
||||
});
|
||||
}
|
||||
|
||||
//when the scope is disposed we need to unsubscribe
|
||||
scope.$on('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valPropertyMsg", valPropertyMsg);
|
||||
@@ -1,78 +1,78 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valRegex
|
||||
* @restrict A
|
||||
* @description A custom directive to allow for matching a value against a regex string.
|
||||
* NOTE: there's already an ng-pattern but this requires that a regex expression is set, not a regex string
|
||||
**/
|
||||
function valRegex() {
|
||||
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
|
||||
var flags = "";
|
||||
var regex;
|
||||
var eventBindings = [];
|
||||
|
||||
attrs.$observe("valRegexFlags", function (newVal) {
|
||||
if (newVal) {
|
||||
flags = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
attrs.$observe("valRegex", function (newVal) {
|
||||
if (newVal) {
|
||||
try {
|
||||
var resolved = newVal;
|
||||
if (resolved) {
|
||||
regex = new RegExp(resolved, flags);
|
||||
}
|
||||
else {
|
||||
regex = new RegExp(attrs.valRegex, flags);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
regex = new RegExp(attrs.valRegex, flags);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
eventBindings.push(scope.$watch('ngModel', function(newValue, oldValue){
|
||||
if(newValue && newValue !== oldValue) {
|
||||
patternValidator(newValue);
|
||||
}
|
||||
}));
|
||||
|
||||
var patternValidator = function (viewValue) {
|
||||
if (regex) {
|
||||
//NOTE: we don't validate on empty values, use required validator for that
|
||||
if (!viewValue || regex.test(viewValue.toString())) {
|
||||
// it is valid
|
||||
ctrl.$setValidity('valRegex', true);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "";
|
||||
return viewValue;
|
||||
}
|
||||
else {
|
||||
// it is invalid, return undefined (no model update)
|
||||
ctrl.$setValidity('valRegex', false);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "Value is invalid, it does not match the correct pattern";
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.$on('$destroy', function(){
|
||||
// unbind watchers
|
||||
for(var e in eventBindings) {
|
||||
eventBindings[e]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valRegex", valRegex);
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valRegex
|
||||
* @restrict A
|
||||
* @description A custom directive to allow for matching a value against a regex string.
|
||||
* NOTE: there's already an ng-pattern but this requires that a regex expression is set, not a regex string
|
||||
**/
|
||||
function valRegex() {
|
||||
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, elm, attrs, ctrl) {
|
||||
|
||||
var flags = "";
|
||||
var regex;
|
||||
var eventBindings = [];
|
||||
|
||||
attrs.$observe("valRegexFlags", function (newVal) {
|
||||
if (newVal) {
|
||||
flags = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
attrs.$observe("valRegex", function (newVal) {
|
||||
if (newVal) {
|
||||
try {
|
||||
var resolved = newVal;
|
||||
if (resolved) {
|
||||
regex = new RegExp(resolved, flags);
|
||||
}
|
||||
else {
|
||||
regex = new RegExp(attrs.valRegex, flags);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
regex = new RegExp(attrs.valRegex, flags);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
eventBindings.push(scope.$watch('ngModel', function(newValue, oldValue){
|
||||
if(newValue && newValue !== oldValue) {
|
||||
patternValidator(newValue);
|
||||
}
|
||||
}));
|
||||
|
||||
var patternValidator = function (viewValue) {
|
||||
if (regex) {
|
||||
//NOTE: we don't validate on empty values, use required validator for that
|
||||
if (!viewValue || regex.test(viewValue.toString())) {
|
||||
// it is valid
|
||||
ctrl.$setValidity('valRegex', true);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "";
|
||||
return viewValue;
|
||||
}
|
||||
else {
|
||||
// it is invalid, return undefined (no model update)
|
||||
ctrl.$setValidity('valRegex', false);
|
||||
//assign a message to the validator
|
||||
ctrl.errorMsg = "Value is invalid, it does not match the correct pattern";
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.$on('$destroy', function(){
|
||||
// unbind watchers
|
||||
for(var e in eventBindings) {
|
||||
eventBindings[e]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valRegex", valRegex);
|
||||
@@ -1,94 +1,94 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServer
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content property with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServer(serverValidationManager) {
|
||||
return {
|
||||
require: ['ngModel', '?^umbProperty'],
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrls) {
|
||||
|
||||
var modelCtrl = ctrls[0];
|
||||
var umbPropCtrl = ctrls.length > 1 ? ctrls[1] : null;
|
||||
if (!umbPropCtrl) {
|
||||
//we cannot proceed, this validator will be disabled
|
||||
return;
|
||||
}
|
||||
|
||||
var watcher = null;
|
||||
|
||||
//Need to watch the value model for it to change, previously we had subscribed to
|
||||
//modelCtrl.$viewChangeListeners but this is not good enough if you have an editor that
|
||||
// doesn't specifically have a 2 way ng binding. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
function startWatch() {
|
||||
//if there's not already a watch
|
||||
if (!watcher) {
|
||||
watcher = scope.$watch(function () {
|
||||
return modelCtrl.$modelValue;
|
||||
}, function (newValue, oldValue) {
|
||||
|
||||
if (!newValue || angular.equals(newValue, oldValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (modelCtrl.$invalid) {
|
||||
modelCtrl.$setValidity('valServer', true);
|
||||
stopWatch();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
function stopWatch() {
|
||||
if (watcher) {
|
||||
watcher();
|
||||
watcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
var currentProperty = umbPropCtrl.property;
|
||||
|
||||
//default to 'value' if nothing is set
|
||||
var fieldName = "value";
|
||||
if (attr.valServer) {
|
||||
fieldName = scope.$eval(attr.valServer);
|
||||
if (!fieldName) {
|
||||
//eval returned nothing so just use the string
|
||||
fieldName = attr.valServer;
|
||||
}
|
||||
}
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
modelCtrl.$setValidity('valServer', false);
|
||||
//assign an error msg property to the current validator
|
||||
modelCtrl.errorMsg = propertyErrors[0].errorMsg;
|
||||
startWatch();
|
||||
}
|
||||
else {
|
||||
modelCtrl.$setValidity('valServer', true);
|
||||
//reset the error message
|
||||
modelCtrl.errorMsg = "";
|
||||
stopWatch();
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
stopWatch();
|
||||
serverValidationManager.unsubscribe(currentProperty.alias, fieldName);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServer
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content property with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServer(serverValidationManager) {
|
||||
return {
|
||||
require: ['ngModel', '?^umbProperty'],
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrls) {
|
||||
|
||||
var modelCtrl = ctrls[0];
|
||||
var umbPropCtrl = ctrls.length > 1 ? ctrls[1] : null;
|
||||
if (!umbPropCtrl) {
|
||||
//we cannot proceed, this validator will be disabled
|
||||
return;
|
||||
}
|
||||
|
||||
var watcher = null;
|
||||
|
||||
//Need to watch the value model for it to change, previously we had subscribed to
|
||||
//modelCtrl.$viewChangeListeners but this is not good enough if you have an editor that
|
||||
// doesn't specifically have a 2 way ng binding. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
function startWatch() {
|
||||
//if there's not already a watch
|
||||
if (!watcher) {
|
||||
watcher = scope.$watch(function () {
|
||||
return modelCtrl.$modelValue;
|
||||
}, function (newValue, oldValue) {
|
||||
|
||||
if (!newValue || angular.equals(newValue, oldValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (modelCtrl.$invalid) {
|
||||
modelCtrl.$setValidity('valServer', true);
|
||||
stopWatch();
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
function stopWatch() {
|
||||
if (watcher) {
|
||||
watcher();
|
||||
watcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
var currentProperty = umbPropCtrl.property;
|
||||
|
||||
//default to 'value' if nothing is set
|
||||
var fieldName = "value";
|
||||
if (attr.valServer) {
|
||||
fieldName = scope.$eval(attr.valServer);
|
||||
if (!fieldName) {
|
||||
//eval returned nothing so just use the string
|
||||
fieldName = attr.valServer;
|
||||
}
|
||||
}
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
modelCtrl.$setValidity('valServer', false);
|
||||
//assign an error msg property to the current validator
|
||||
modelCtrl.errorMsg = propertyErrors[0].errorMsg;
|
||||
startWatch();
|
||||
}
|
||||
else {
|
||||
modelCtrl.$setValidity('valServer', true);
|
||||
//reset the error message
|
||||
modelCtrl.errorMsg = "";
|
||||
stopWatch();
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
stopWatch();
|
||||
serverValidationManager.unsubscribe(currentProperty.alias, fieldName);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valServer", valServer);
|
||||
@@ -1,65 +1,65 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServerField
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content field (not user defined) with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServerField(serverValidationManager) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
var fieldName = null;
|
||||
var eventBindings = [];
|
||||
|
||||
attr.$observe("valServerField", function (newVal) {
|
||||
if (newVal && fieldName === null) {
|
||||
fieldName = newVal;
|
||||
|
||||
//subscribe to the changed event of the view model. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
eventBindings.push(scope.$watch('ngModel', function(newValue){
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
}
|
||||
}));
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
ctrl.$setValidity('valServerField', false);
|
||||
//assign an error msg property to the current validator
|
||||
ctrl.errorMsg = fieldErrors[0].errorMsg;
|
||||
}
|
||||
else {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
//reset the error message
|
||||
ctrl.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
serverValidationManager.unsubscribe(null, fieldName);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function(){
|
||||
// unbind watchers
|
||||
for(var e in eventBindings) {
|
||||
eventBindings[e]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valServerField", valServerField);
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valServerField
|
||||
* @restrict A
|
||||
* @description This directive is used to associate a content field (not user defined) with a server-side validation response
|
||||
* so that the validators in angular are updated based on server-side feedback.
|
||||
**/
|
||||
function valServerField(serverValidationManager) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
|
||||
var fieldName = null;
|
||||
var eventBindings = [];
|
||||
|
||||
attr.$observe("valServerField", function (newVal) {
|
||||
if (newVal && fieldName === null) {
|
||||
fieldName = newVal;
|
||||
|
||||
//subscribe to the changed event of the view model. This is required because when we
|
||||
// have a server error we actually invalidate the form which means it cannot be
|
||||
// resubmitted. So once a field is changed that has a server error assigned to it
|
||||
// we need to re-validate it for the server side validator so the user can resubmit
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
eventBindings.push(scope.$watch('ngModel', function(newValue){
|
||||
if (ctrl.$invalid) {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
}
|
||||
}));
|
||||
|
||||
//subscribe to the server validation changes
|
||||
serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) {
|
||||
if (!isValid) {
|
||||
ctrl.$setValidity('valServerField', false);
|
||||
//assign an error msg property to the current validator
|
||||
ctrl.errorMsg = fieldErrors[0].errorMsg;
|
||||
}
|
||||
else {
|
||||
ctrl.$setValidity('valServerField', true);
|
||||
//reset the error message
|
||||
ctrl.errorMsg = "";
|
||||
}
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain
|
||||
// but they are a different callback instance than the above.
|
||||
element.bind('$destroy', function () {
|
||||
serverValidationManager.unsubscribe(null, fieldName);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function(){
|
||||
// unbind watchers
|
||||
for(var e in eventBindings) {
|
||||
eventBindings[e]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valServerField", valServerField);
|
||||
@@ -1,38 +1,38 @@
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valTab
|
||||
* @restrict A
|
||||
* @description Used to show validation warnings for a tab to indicate that the tab content has validations errors in its data.
|
||||
* In order for this directive to work, the valFormManager directive must be placed on the containing form.
|
||||
**/
|
||||
function valTab() {
|
||||
return {
|
||||
require: ['^form', '^valFormManager'],
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrs) {
|
||||
|
||||
var valFormManager = ctrs[1];
|
||||
var tabId = "tab" + scope.tab.id;
|
||||
scope.tabHasError = false;
|
||||
|
||||
//listen for form validation changes
|
||||
valFormManager.onValidationStatusChanged(function (evt, args) {
|
||||
if (!args.form.$valid) {
|
||||
var tabContent = element.closest(".umb-panel").find("#" + tabId);
|
||||
//check if the validation messages are contained inside of this tabs
|
||||
if (tabContent.find(".ng-invalid").length > 0) {
|
||||
scope.tabHasError = true;
|
||||
} else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valTab
|
||||
* @restrict A
|
||||
* @description Used to show validation warnings for a tab to indicate that the tab content has validations errors in its data.
|
||||
* In order for this directive to work, the valFormManager directive must be placed on the containing form.
|
||||
**/
|
||||
function valTab() {
|
||||
return {
|
||||
require: ['^form', '^valFormManager'],
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, ctrs) {
|
||||
|
||||
var valFormManager = ctrs[1];
|
||||
var tabId = "tab" + scope.tab.id;
|
||||
scope.tabHasError = false;
|
||||
|
||||
//listen for form validation changes
|
||||
valFormManager.onValidationStatusChanged(function (evt, args) {
|
||||
if (!args.form.$valid) {
|
||||
var tabContent = element.closest(".umb-panel").find("#" + tabId);
|
||||
//check if the validation messages are contained inside of this tabs
|
||||
if (tabContent.find(".ng-invalid").length > 0) {
|
||||
scope.tabHasError = true;
|
||||
} else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope.tabHasError = false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
angular.module('umbraco.directives.validation').directive("valTab", valTab);
|
||||
@@ -1,90 +1,90 @@
|
||||
function valToggleMsg(serverValidationManager) {
|
||||
return {
|
||||
require: "^form",
|
||||
restrict: "A",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
if (!attr.valToggleMsg){
|
||||
throw "valToggleMsg requires that a reference to a validator is specified";
|
||||
}
|
||||
if (!attr.valMsgFor){
|
||||
throw "valToggleMsg requires that the attribute valMsgFor exists on the element";
|
||||
}
|
||||
if (!formCtrl[attr.valMsgFor]) {
|
||||
throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name;
|
||||
}
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
var hasCustomMsg = element.contents().length > 0;
|
||||
|
||||
//add a watch to the validator for the value (i.e. myForm.value.$error.required )
|
||||
scope.$watch(function () {
|
||||
//sometimes if a dialog closes in the middle of digest we can get null references here
|
||||
|
||||
return (formCtrl && formCtrl[attr.valMsgFor]) ? formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] : null;
|
||||
}, function () {
|
||||
//sometimes if a dialog closes in the middle of digest we can get null references here
|
||||
if ((formCtrl && formCtrl[attr.valMsgFor])) {
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) {
|
||||
element.show();
|
||||
//display the error message if this element has no contents
|
||||
if (!hasCustomMsg) {
|
||||
element.html(formCtrl[attr.valMsgFor].errorMsg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the saving event (the result is a callback method which is called to unsubscribe)
|
||||
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
|
||||
element.show();
|
||||
//display the error message if this element has no contents
|
||||
if (!hasCustomMsg) {
|
||||
element.html(formCtrl[attr.valMsgFor].errorMsg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
}));
|
||||
|
||||
//listen for the saved event (the result is a callback method which is called to unsubscribe)
|
||||
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
|
||||
showValidation = false;
|
||||
element.hide();
|
||||
}));
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise if this directive is part of a modal, the listener still exists because the dom
|
||||
// element might still be there even after the modal has been hidden.
|
||||
element.bind('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valToggleMsg
|
||||
* @restrict A
|
||||
* @element input
|
||||
* @requires formController
|
||||
* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ?
|
||||
**/
|
||||
function valToggleMsg(serverValidationManager) {
|
||||
return {
|
||||
require: "^form",
|
||||
restrict: "A",
|
||||
|
||||
/**
|
||||
Our directive requries a reference to a form controller which gets passed in to this parameter
|
||||
*/
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
if (!attr.valToggleMsg){
|
||||
throw "valToggleMsg requires that a reference to a validator is specified";
|
||||
}
|
||||
if (!attr.valMsgFor){
|
||||
throw "valToggleMsg requires that the attribute valMsgFor exists on the element";
|
||||
}
|
||||
if (!formCtrl[attr.valMsgFor]) {
|
||||
throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name;
|
||||
}
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
var hasCustomMsg = element.contents().length > 0;
|
||||
|
||||
//add a watch to the validator for the value (i.e. myForm.value.$error.required )
|
||||
scope.$watch(function () {
|
||||
//sometimes if a dialog closes in the middle of digest we can get null references here
|
||||
|
||||
return (formCtrl && formCtrl[attr.valMsgFor]) ? formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] : null;
|
||||
}, function () {
|
||||
//sometimes if a dialog closes in the middle of digest we can get null references here
|
||||
if ((formCtrl && formCtrl[attr.valMsgFor])) {
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) {
|
||||
element.show();
|
||||
//display the error message if this element has no contents
|
||||
if (!hasCustomMsg) {
|
||||
element.html(formCtrl[attr.valMsgFor].errorMsg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the saving event (the result is a callback method which is called to unsubscribe)
|
||||
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
|
||||
showValidation = true;
|
||||
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
|
||||
element.show();
|
||||
//display the error message if this element has no contents
|
||||
if (!hasCustomMsg) {
|
||||
element.html(formCtrl[attr.valMsgFor].errorMsg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
element.hide();
|
||||
}
|
||||
}));
|
||||
|
||||
//listen for the saved event (the result is a callback method which is called to unsubscribe)
|
||||
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
|
||||
showValidation = false;
|
||||
element.hide();
|
||||
}));
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise if this directive is part of a modal, the listener still exists because the dom
|
||||
// element might still be there even after the modal has been hidden.
|
||||
element.bind('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:valToggleMsg
|
||||
* @restrict A
|
||||
* @element input
|
||||
* @requires formController
|
||||
* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ?
|
||||
**/
|
||||
angular.module('umbraco.directives.validation').directive("valToggleMsg", valToggleMsg);
|
||||
Reference in New Issue
Block a user