Optimize validation routine

Only validate the property being edited, not the entire fieldset the
property belongs to.
This commit is contained in:
kjac
2014-05-21 22:49:15 +02:00
parent c8d9b04a57
commit 1bfab0f8a3
+54 -51
View File
@@ -56,9 +56,9 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
var alias = configFieldsetModel.properties[scope.propertyConfigIndex].alias;
var defaultValue = configFieldsetModel.properties[scope.propertyConfigIndex].value;
var umbracoPropertyAlias = scope.umbracoPropertyAlias;
// initialize container for invalid fieldset identifiers (store on ngModelCtrl to separate Archetype validations, e.g. when there two Archetype properties on the same document)
if(ngModelCtrl.invalidFieldsets == null) {
ngModelCtrl.invalidFieldsets = [];
// initialize container for invalid fieldset property identifiers (store on ngModelCtrl to separate Archetype validations, e.g. when there two Archetype properties on the same document)
if(ngModelCtrl.invalidProperties == null) {
ngModelCtrl.invalidProperties = [];
}
//try to convert the defaultValue to a JS object
@@ -85,74 +85,77 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
var mergedConfig = _.extend(defaultConfigObj, config);
loadView(pathToView, mergedConfig, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl, validate);
loadView(pathToView, mergedConfig, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl, validateProperty);
});
});
scope.$on("formSubmitting", function (ev, args) {
// "hard" validate to highlight any erroneous entries
validate([scope.fieldset], true);
_.each(scope.fieldset.properties, function (property) {
validateProperty(scope.fieldset, property, true);
});
});
scope.$on("formSubmitted", function (ev, args) {
ngModelCtrl.invalidFieldsets = [];
// reset the nested fieldset validation state after submit
ngModelCtrl.invalidProperties = [];
});
function validate(renderModel, markAsInvalid){
if(renderModel == undefined) {
return renderModel;
}
// need to pass the property fieldset here to clear any invalid state of the fieldset when validating a single fieldset property
// - it's the Umbraco way to hide the invalid state when altering an invalid property, even if the new value isn't valid either
function validateProperty(fieldset, property, markAsInvalid) {
var valid = true;
_.each(renderModel, function(fieldset){
fieldset.isValid = true;
_.each(fieldset.properties, function(property){
property.isValid = true;
var propertyValid = true;
var propertyConfig = getPropertyByAlias(configFieldsetModel, property.alias);
if (propertyConfig) {
// use property.value !== property.value to check for NaN values on numeric inputs
if(propertyConfig.required && (property.value == null || property.value === "" || property.value !== property.value)) {
valid = false;
propertyValid = false;
}
// issue 116: RegEx validate property value
// Only validate the property value if anything has been entered - RegEx is considered a supplement to "required".
if (valid == true && propertyConfig.regEx && property.value) {
var regEx = new RegExp(propertyConfig.regEx);
if (regEx.test(property.value) == false) {
valid = false;
propertyValid = false;
}
}
// only mark the fieldset and property as invalid when doing a "hard" validation
if(propertyValid == false && markAsInvalid == true) {
fieldset.isValid = false;
property.isValid = false;
}
fieldset.isValid = true;
property.isValid = true;
var propertyConfig = getPropertyByAlias(configFieldsetModel, property.alias);
if (propertyConfig) {
// use property.value !== property.value to check for NaN values on numeric inputs
if (propertyConfig.required && (property.value == null || property.value === "" || property.value !== property.value)) {
valid = false;
}
// issue 116: RegEx validate property value
// Only validate the property value if anything has been entered - RegEx is considered a supplement to "required".
if (valid == true && propertyConfig.regEx && property.value) {
var regEx = new RegExp(propertyConfig.regEx);
if (regEx.test(property.value) == false) {
valid = false;
}
});
});
}
// only mark the property as invalid when doing a "hard" validation
if (valid == false && markAsInvalid == true) {
property.isValid = false;
}
}
// handle nested fieldset validation by storing the identifier of all invalid fieldsets
// handle nested fieldset validation by storing the identifier of all invalid fieldset properties
var fieldsetIdentifier = scope.umbracoPropertyAlias + "_" + scope.fieldsetIndex;
var fieldsetIdentifierIndex = ngModelCtrl.invalidFieldsets.indexOf(fieldsetIdentifier);
if(valid == false) {
if(fieldsetIdentifierIndex == -1) {
ngModelCtrl.invalidFieldsets.push(fieldsetIdentifier);
var propertyIdentifier = fieldsetIdentifier + "_" + property.alias;
var propertyIdentifierIndex = ngModelCtrl.invalidProperties.indexOf(propertyIdentifier);
if (valid == false) {
if (propertyIdentifierIndex == -1) {
ngModelCtrl.invalidProperties.push(propertyIdentifier);
}
}
else {
if(fieldsetIdentifierIndex != -1) {
ngModelCtrl.invalidFieldsets.splice(fieldsetIdentifierIndex, 1);
if (propertyIdentifierIndex != -1) {
ngModelCtrl.invalidProperties.splice(propertyIdentifierIndex, 1);
}
}
// set invalid state if one or more fieldsets contain invalid entries
ngModelCtrl.$setValidity('validation', ngModelCtrl.invalidFieldsets.length == 0);
return renderModel;
if (markAsInvalid) {
// mark the entire fieldset as invalid if there are any invalid properties in the fieldset, otherwise mark it as valid
fieldset.isValid =
_.find(ngModelCtrl.invalidProperties, function (item) {
return item.indexOf(fieldsetIdentifier) == 0
}) == null;
}
// set invalid state if one or more fieldsets contain invalid properties
ngModelCtrl.$setValidity('validation', ngModelCtrl.invalidProperties.length == 0);
}
}
function loadView(view, config, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl, validate) {
function loadView(view, config, defaultValue, alias, umbracoPropertyAlias, scope, element, ngModelCtrl, validateProperty) {
if (view)
{
$http.get(view).success(function (data) {
@@ -187,9 +190,9 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
scope.$watch('model.value', function (newValue, oldValue) {
scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties[renderModelPropertyIndex].value = newValue;
// call validation method for this fieldset when a property value changes
// call validation method for the property when the value changes
// use "soft" validation to mimic the default umbraco validation style (show error highlights on submit, not while entering data)
validate([scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex]], false);
validateProperty(scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex], scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties[renderModelPropertyIndex], false);
});
element.html(data).show();