Getting close, adds tests, fixese the key being set on the block, gets errors clearing, now need to make the UI behave.
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
},
|
||||
bindings: {
|
||||
property: "=",
|
||||
elementUdi: "@",
|
||||
elementKey: "@",
|
||||
// optional, if set this will be used for the property alias validation path (hack required because NC changes the actual property.alias :/)
|
||||
propertyAlias: "@",
|
||||
showInherit: "<",
|
||||
@@ -44,20 +44,14 @@
|
||||
vm.propertyActions = actions;
|
||||
};
|
||||
|
||||
// returns the unique Id for the property to be used as the validation key for server side validation logic
|
||||
// returns the validation path for the property to be used as the validation key for server side validation logic
|
||||
vm.getValidationPath = function () {
|
||||
|
||||
// the elementUdi will be empty when this is not a nested property
|
||||
var parentValidationPath = vm.parentUmbProperty ? vm.parentUmbProperty.getValidationPath() : null;
|
||||
var propAlias = vm.propertyAlias ? vm.propertyAlias : vm.property.alias;
|
||||
vm.elementUdi = ensureUdi(vm.elementUdi);
|
||||
return serverValidationManager.createPropertyValidationKey(propAlias, vm.elementUdi);
|
||||
}
|
||||
|
||||
vm.getParentValidationPath = function () {
|
||||
if (!vm.parentUmbProperty) {
|
||||
return null;
|
||||
}
|
||||
return vm.parentUmbProperty.getValidationPath();
|
||||
// the elementKey will be empty when this is not a nested property
|
||||
var valPath = vm.elementKey ? vm.elementKey + "/" + propAlias : propAlias;
|
||||
return serverValidationManager.createPropertyValidationKey(valPath, parentValidationPath);
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
@@ -70,8 +64,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
vm.elementUdi = ensureUdi(vm.elementUdi);
|
||||
|
||||
if (!vm.parentUmbProperty) {
|
||||
// not found, then fallback to searching the scope chain, this may be needed when DOM inheritance isn't maintained but scope
|
||||
// inheritance is (i.e.infinite editing)
|
||||
@@ -80,13 +72,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// if only a guid is passed in, we'll ensure a correct udi structure
|
||||
function ensureUdi(udi) {
|
||||
if (udi && !udi.startsWith("umb://")) {
|
||||
udi = udiService.build("element", udi);
|
||||
}
|
||||
return udi;
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
@@ -24,6 +24,7 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
var unsubscribe = [];
|
||||
var watcher = null;
|
||||
var hasError = false;
|
||||
var hasServerError = false; // tracks if this validator has an explicit server validator key attached to it
|
||||
|
||||
//create properties on our custom scope so we can use it in our template
|
||||
scope.errorMsg = "";
|
||||
@@ -49,9 +50,6 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
var isMandatory = currentProperty.validation ? currentProperty.validation.mandatory : undefined;
|
||||
|
||||
var labels = {};
|
||||
localizationService.localize("errors_propertyHasErrors").then(function (data) {
|
||||
labels.propertyHasErrors = data;
|
||||
});
|
||||
|
||||
if (umbVariantCtrl) {
|
||||
//if we are inside of an umbVariantContent directive
|
||||
@@ -69,7 +67,6 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
// if we have reached this part, and there is no culture, then lets fallback to invariant. To get the validation feedback for invariant language.
|
||||
currentCulture = currentCulture || "invariant";
|
||||
|
||||
|
||||
// Gets the error message to display
|
||||
function getErrorMsg() {
|
||||
//this can be null if no property was assigned
|
||||
@@ -96,11 +93,6 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
// the form. Of course normal client-side validators will continue to execute.
|
||||
function startWatch() {
|
||||
|
||||
// TODO: Can we watch on something other than the value?? This doesn't work for complex editors especially once that have a
|
||||
// viewmodel/model setup the value that this is watching doesn't actually get updated by a sub-editor in all cases.
|
||||
// we can probably watch the formCtrl view value? But then we also don't want this to watch complex values that have sub editors anyways
|
||||
// since that might end up clearing the whole chain of valPropertyMsg when a sub value is changed (in some cases, not with the block editor).
|
||||
|
||||
//if there's not already a watch
|
||||
|
||||
if (!watcher) {
|
||||
@@ -125,6 +117,25 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
if (errCount === 0
|
||||
|| (errCount === 1 && Utilities.isArray(formCtrl.$error.valPropertyMsg))
|
||||
|| (formCtrl.$invalid && Utilities.isArray(formCtrl.$error.valServer))) {
|
||||
|
||||
console.log("RESETTING ERROR FROM WATCH " + propertyValidationKey + " - " + hasServerError);
|
||||
|
||||
if (hasServerError) {
|
||||
|
||||
// check if we can clear it based on child server errors, if we are the only explicit one remaining we can clear ourselves
|
||||
var nestedErrs = serverValidationManager.getPropertyErrorsByValidationPath(
|
||||
propertyValidationKey,
|
||||
currentCulture,
|
||||
"",
|
||||
currentSegment,
|
||||
true);
|
||||
if (nestedErrs.length === 1 && nestedErrs[0].propertyAlias === propertyValidationKey) {
|
||||
|
||||
console.log("CLEARING SERVER VAL FROM WATCH " + propertyValidationKey);
|
||||
serverValidationManager.removePropertyError(propertyValidationKey, currentCulture, "", currentSegment);
|
||||
}
|
||||
}
|
||||
|
||||
resetError();
|
||||
}
|
||||
else if (showValidation && scope.errorMsg === "") {
|
||||
@@ -144,104 +155,18 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
}
|
||||
|
||||
function resetError() {
|
||||
var hadError = hasError;
|
||||
hasError = false;
|
||||
formCtrl.$setValidity('valPropertyMsg', true, formCtrl);
|
||||
scope.errorMsg = "";
|
||||
stopWatch();
|
||||
|
||||
// if we had an error, then check on the current valFormManager to see if it's
|
||||
// now valid, if it is it means that the containing form (i.e. the form rendering)
|
||||
// properties for an element/content type) is now valid which means we can clear
|
||||
// the parent's valPropertyMsg if there is one. This will only occur with complex editors
|
||||
// where we have nested umb-property components.
|
||||
if (hadError) {
|
||||
scope.$evalAsync(function () {
|
||||
|
||||
//// TODO: This does not work :( :( :(
|
||||
//// We cannot clear a val-property-msg because another nested child might have server validation errors too.
|
||||
//// I 'think' we might be able to set the UI validation of this val-property-msg based on the child validators as well
|
||||
//// as the server validator so it can 'just' unset itself if all child validators are cleared. Can it be done?
|
||||
|
||||
//// Here we loop over the umbProperty hierarchy to see if we should clear the val-property-msg server validation key.
|
||||
//// we will clear the key if the parent for is valid, or if the parent form is only invalid due to a single val-property-msg error.
|
||||
//var currUmbProperty = umbPropCtrl;
|
||||
//var parentValidationKey = currUmbProperty.getParentValidationPath();
|
||||
//while (currUmbProperty && parentValidationKey) {
|
||||
|
||||
// if (!currUmbProperty.parentForm.$invalid || (_.keys(currUmbProperty.parentForm.$error).length === 1 && currUmbProperty.parentForm.$error.valPropertyMsg)) {
|
||||
// serverValidationManager.removePropertyError(parentValidationKey, currentCulture, "", currentSegment);
|
||||
|
||||
// // re-assign and loop
|
||||
// if (currUmbProperty !== umbPropCtrl.parentUmbProperty) {
|
||||
// currUmbProperty = umbPropCtrl.parentUmbProperty;
|
||||
// parentValidationKey = currUmbProperty ? currUmbProperty.getParentValidationPath() : null;
|
||||
// }
|
||||
// else {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
//// we need to navigate the parentForm here, unfortunately there's no real alternative unless we create our own directive
|
||||
//// of some sort but that would also get messy. This works though since in this case we're always going to be in the property
|
||||
//// form and the parent form about this will contain any invalid flags for all the other sibling properties. So when that is
|
||||
//// no longer invalid, we can check if we have a parent validation key (meaning we'd be nested inside of umb-property) and
|
||||
//// we can clear that server error.
|
||||
//// TODO: If there is another server error for this property though this might clear it inadvertently, at this time I'm unsure how to deal with that.
|
||||
//var parentValidationKey = umbPropCtrl.getParentValidationPath();
|
||||
//if (parentValidationKey) {
|
||||
// // TODO: Instead of using the parent form, can we 'just' use umbProperty again which itself can check if it's
|
||||
// // parent form is valid? then below we can call in a loop each parent umb property check if it has a parent validation
|
||||
// // path and check if it's form is valid, this will recursively perform this logic up the chain.
|
||||
// var parentForm = formCtrl.$$parentForm;
|
||||
// if (parentForm && !parentForm.$invalid) {
|
||||
// // TODO: Though this works for one level, if you have errors at level 1 and 2, clear errors at level when
|
||||
// // and then level 2, then only the val-property-msg is cleared at level 1 and not also at level 0.
|
||||
// // So we still need to recurse up the chain to deal with this
|
||||
// serverValidationManager.removePropertyError(parentValidationKey, currentCulture, "", currentSegment);
|
||||
// }
|
||||
//}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//function checkFormValidation(f) {
|
||||
|
||||
// if (!angularHelper.isForm(f)) {
|
||||
// throw "The object is not an angular Form";
|
||||
// }
|
||||
|
||||
// // if there's no value, the controls can be reset, which clears the error state on formCtrl
|
||||
// for (let control of formCtrl.$getControls()) {
|
||||
// control.$setValidity();
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
function checkValidationStatus() {
|
||||
if (formCtrl.$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
|
||||
|
||||
// TODO: This does not work! we cannot just clear if there are no errors in child controls because child controls
|
||||
// won't even have been loaded yet so this will just instantly clear them
|
||||
//// At this stage we might have an error assigned because it was assigned based on validation hierarchy from the server,
|
||||
//// BUT one or ALL of the child server (and client) validations may be cleared at this point. We will know if we have an
|
||||
//// explicitly assigned error based on the error message assigned, if it is a non-explicit error (meaning that the error
|
||||
//// was assigned because it has child errors) then the message will just be: labels.propertyHasErrors
|
||||
//if (scope.errorMsg === labels.propertyHasErrors && _.every(formCtrl.$getControls(), c => c.$valid)) {
|
||||
// resetError();
|
||||
//}
|
||||
|
||||
//hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe
|
||||
return;
|
||||
}
|
||||
//if there are any errors in the current property form that are not valPropertyMsg
|
||||
@@ -275,73 +200,92 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
}
|
||||
}
|
||||
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
if (!showValidation) {
|
||||
//We can either get the form submitted status by the parent directive valFormManager (if we add a property to it)
|
||||
//or we can just check upwards in the DOM for the css class (easier for now).
|
||||
//The initial hidden state can't always be hidden because when we switch variants in the content editor we cannot
|
||||
//reset the status.
|
||||
showValidation = element.closest(".show-validation").length > 0;
|
||||
}
|
||||
function onInit() {
|
||||
|
||||
localizationService.localize("errors_propertyHasErrors").then(function (data) {
|
||||
|
||||
//listen for form validation changes.
|
||||
//The alternative is to add a watch to formCtrl.$invalid but that would lead to many more watches then
|
||||
// subscribing to this single watch.
|
||||
valFormManager.onValidationStatusChanged(function (evt, args) {
|
||||
checkValidationStatus();
|
||||
});
|
||||
labels.propertyHasErrors = data;
|
||||
|
||||
//listen for the forms saving event
|
||||
unsubscribe.push(scope.$on("formSubmitting", function (ev, args) {
|
||||
showValidation = true;
|
||||
if (hasError && scope.errorMsg === "") {
|
||||
scope.errorMsg = getErrorMsg();
|
||||
startWatch();
|
||||
}
|
||||
else if (!hasError) {
|
||||
resetError();
|
||||
}
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
unsubscribe.push(scope.$on("formSubmitted", function (ev, args) {
|
||||
showValidation = false;
|
||||
resetError();
|
||||
}));
|
||||
|
||||
//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.currentProperty) { //this can be null if no property was assigned
|
||||
|
||||
function serverValidationManagerCallback(isValid, propertyErrors, allErrors) {
|
||||
hasError = !isValid;
|
||||
if (hasError) {
|
||||
//set the error message to the server message
|
||||
scope.errorMsg = propertyErrors[0].errorMsg ? propertyErrors[0].errorMsg : labels.propertyHasErrors;
|
||||
//flag that the current validator is invalid
|
||||
formCtrl.$setValidity('valPropertyMsg', false, formCtrl);
|
||||
startWatch();
|
||||
//if there's any remaining errors in the server validation service then we should show them.
|
||||
var showValidation = serverValidationManager.items.length > 0;
|
||||
if (!showValidation) {
|
||||
//We can either get the form submitted status by the parent directive valFormManager (if we add a property to it)
|
||||
//or we can just check upwards in the DOM for the css class (easier for now).
|
||||
//The initial hidden state can't always be hidden because when we switch variants in the content editor we cannot
|
||||
//reset the status.
|
||||
showValidation = element.closest(".show-validation").length > 0;
|
||||
}
|
||||
else {
|
||||
|
||||
//listen for form validation changes.
|
||||
//The alternative is to add a watch to formCtrl.$invalid but that would lead to many more watches then
|
||||
// subscribing to this single watch.
|
||||
valFormManager.onValidationStatusChanged(function (evt, args) {
|
||||
checkValidationStatus();
|
||||
});
|
||||
|
||||
//listen for the forms saving event
|
||||
unsubscribe.push(scope.$on("formSubmitting", function (ev, args) {
|
||||
showValidation = true;
|
||||
if (hasError && scope.errorMsg === "") {
|
||||
scope.errorMsg = getErrorMsg();
|
||||
startWatch();
|
||||
}
|
||||
else if (!hasError) {
|
||||
resetError();
|
||||
}
|
||||
}));
|
||||
|
||||
//listen for the forms saved event
|
||||
unsubscribe.push(scope.$on("formSubmitted", function (ev, args) {
|
||||
showValidation = false;
|
||||
resetError();
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
unsubscribe.push(serverValidationManager.subscribe(
|
||||
propertyValidationKey,
|
||||
currentCulture,
|
||||
"",
|
||||
serverValidationManagerCallback,
|
||||
currentSegment
|
||||
));
|
||||
if (scope.currentProperty) { //this can be null if no property was assigned
|
||||
|
||||
//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.
|
||||
|
||||
function serverValidationManagerCallback(isValid, propertyErrors, allErrors) {
|
||||
var hadError = hasError;
|
||||
hasError = !isValid;
|
||||
if (hasError) {
|
||||
|
||||
// check if one of the errors is explicitly assigned to our validation key
|
||||
hasServerError = _.some(propertyErrors, x => x.propertyAlias === propertyValidationKey);
|
||||
if (hadError && hasServerError && propertyErrors.length === 1) {
|
||||
// we're the only error remaining in the server validation
|
||||
console.log("ONLY ERROR REMAINING " + propertyValidationKey);
|
||||
}
|
||||
|
||||
//set the error message to the server message
|
||||
scope.errorMsg = propertyErrors[0].errorMsg ? propertyErrors[0].errorMsg : labels.propertyHasErrors;
|
||||
//flag that the current validator is invalid
|
||||
console.log("valPropertyMsg invalid - " + propertyValidationKey);
|
||||
formCtrl.$setValidity('valPropertyMsg', false, formCtrl);
|
||||
startWatch();
|
||||
}
|
||||
else {
|
||||
resetError();
|
||||
}
|
||||
}
|
||||
|
||||
unsubscribe.push(serverValidationManager.subscribe(
|
||||
propertyValidationKey,
|
||||
currentCulture,
|
||||
"",
|
||||
serverValidationManagerCallback,
|
||||
currentSegment,
|
||||
true // match property validation path prefix
|
||||
));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
//when the scope is disposed we need to unsubscribe
|
||||
@@ -351,6 +295,8 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
onInit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -82,6 +82,7 @@ function valServer(serverValidationManager) {
|
||||
|
||||
//clear the server validation entry
|
||||
serverValidationManager.removePropertyError(propertyValidationPath, currentCulture, fieldName, currentSegment);
|
||||
|
||||
stopWatch();
|
||||
}
|
||||
}, true);
|
||||
|
||||
@@ -375,7 +375,7 @@
|
||||
* @name getBlockObject
|
||||
* @methodOf umbraco.services.blockEditorModelObject
|
||||
* @description Retrieve a Block Object for the given layout entry.
|
||||
* The Block Object offers the nesecary data to display and edit a block.
|
||||
* The Block Object offers the necessary data to display and edit a block.
|
||||
* The Block Object setups live syncronization of content and settings models back to the data of your Property Editor model.
|
||||
* The returned object, named ´BlockObject´, contains several usefull models to make editing of this block happen.
|
||||
* The ´BlockObject´ contains the following properties:
|
||||
@@ -448,6 +448,8 @@
|
||||
// make basics from scaffold
|
||||
blockObject.content = Utilities.copy(contentScaffold);
|
||||
blockObject.content.udi = udi;
|
||||
// Change the content.key to the GUID part of the udi, else it's just random which we don't want, it should be consistent
|
||||
blockObject.content.key = udiService.getKey(udi);
|
||||
|
||||
mapToElementModel(blockObject.content, dataModel);
|
||||
|
||||
|
||||
@@ -52,6 +52,9 @@ function serverValidationManager($timeout) {
|
||||
* Notifies all subscriptions again. Called when there are changes to subscriptions or errors.
|
||||
*/
|
||||
function notify() {
|
||||
|
||||
console.log("NOTIFY!");
|
||||
|
||||
$timeout(function () {
|
||||
|
||||
console.log(`VAL-ERROR-COUNT: ${items.length}`);
|
||||
@@ -92,7 +95,8 @@ function serverValidationManager($timeout) {
|
||||
|
||||
//find all errors for this property
|
||||
return _.filter(items, function (item) {
|
||||
return ((matchPrefixValidationPath ? (item.propertyAlias === propertyAlias || propertyAlias.startsWith(item.propertyAlias + '/')) : item.propertyAlias === propertyAlias)
|
||||
return ((matchPrefixValidationPath ? (item.propertyAlias === propertyAlias || (item.propertyAlias && item.propertyAlias.startsWith(propertyAlias + '/'))) : item.propertyAlias === propertyAlias)
|
||||
//return ((matchPrefixValidationPath ? (item.propertyAlias === propertyAlias || propertyAlias.startsWith(item.propertyAlias + '/')) : item.propertyAlias === propertyAlias)
|
||||
&& item.culture === culture
|
||||
&& item.segment === segment
|
||||
// ignore field matching if
|
||||
@@ -115,29 +119,36 @@ function serverValidationManager($timeout) {
|
||||
});
|
||||
}
|
||||
|
||||
function notifyCallback(cb) {
|
||||
if (cb.propertyAlias === null && cb.fieldName !== null) {
|
||||
//its a field error callback
|
||||
const fieldErrors = getFieldErrors(cb.fieldName);
|
||||
const valid = fieldErrors.length === 0;
|
||||
executeCallback(fieldErrors, cb.callback, cb.culture, cb.segment, valid);
|
||||
}
|
||||
else if (cb.propertyAlias != null) {
|
||||
//its a property error
|
||||
const propErrors = getPropertyErrors(cb.propertyAlias, cb.culture, cb.segment, cb.fieldName, cb.matchPrefix);
|
||||
const valid = propErrors.length === 0;
|
||||
executeCallback(propErrors, cb.callback, cb.culture, cb.segment, valid);
|
||||
}
|
||||
else {
|
||||
//its a variant error
|
||||
const variantErrors = getVariantErrors(cb.culture, cb.segment);
|
||||
const valid = variantErrors.length === 0;
|
||||
executeCallback(variantErrors, cb.callback, cb.culture, cb.segment, valid);
|
||||
}
|
||||
}
|
||||
|
||||
/** Call all registered callbacks indicating if the data they are subscribed to is valid or invalid */
|
||||
function notifyCallbacks() {
|
||||
|
||||
callbacks.forEach(cb => {
|
||||
if (cb.propertyAlias === null && cb.fieldName !== null) {
|
||||
//its a field error callback
|
||||
const fieldErrors = getFieldErrors(cb.fieldName);
|
||||
const valid = fieldErrors.length === 0;
|
||||
executeCallback(fieldErrors, cb.callback, cb.culture, cb.segment, valid);
|
||||
}
|
||||
else if (cb.propertyAlias != null) {
|
||||
//its a property error
|
||||
const propErrors = getPropertyErrors(cb.propertyAlias, cb.culture, cb.segment, cb.fieldName, cb.matchPrefix);
|
||||
const valid = propErrors.length === 0;
|
||||
executeCallback(propErrors, cb.callback, cb.culture, cb.segment, valid);
|
||||
}
|
||||
else {
|
||||
//its a variant error
|
||||
const variantErrors = getVariantErrors(cb.culture, cb.segment);
|
||||
const valid = variantErrors.length === 0;
|
||||
executeCallback(variantErrors, cb.callback, cb.culture, cb.segment, valid);
|
||||
}
|
||||
});
|
||||
// nothing to call
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
callbacks.forEach(cb => notifyCallback(cb));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -343,29 +354,7 @@ function serverValidationManager($timeout) {
|
||||
});
|
||||
}
|
||||
|
||||
//find all errors for this item
|
||||
var propertyErrors = getPropertyErrors(propertyAlias, culture, segment, fieldName);
|
||||
var propertyPrefixErrors = getPropertyErrors(propertyAlias, culture, segment, fieldName, true);
|
||||
|
||||
//now call all of the call backs registered for this error
|
||||
var cbs = getPropertyCallbacks(propertyAlias, culture, fieldName, segment);
|
||||
|
||||
//call each callback for this error
|
||||
cbs.forEach(cb => {
|
||||
if (cb.matchPrefix) {
|
||||
executeCallback(propertyPrefixErrors, cb.callback, culture, segment, false);
|
||||
}
|
||||
else {
|
||||
executeCallback(propertyErrors, cb.callback, culture, segment, false);
|
||||
}
|
||||
});
|
||||
|
||||
//execute variant specific callbacks here too when a propery error is added
|
||||
var variantCbs = getVariantCallbacks(culture, segment);
|
||||
//call each callback for this error
|
||||
variantCbs.forEach(cb => {
|
||||
executeCallback(propertyErrors, cb.callback, culture, segment, false);
|
||||
});
|
||||
notifyCallbacks();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,30 +591,33 @@ function serverValidationManager($timeout) {
|
||||
segment = null;
|
||||
}
|
||||
|
||||
if (propertyAlias === null) {
|
||||
let cb = null;
|
||||
|
||||
callbacks.push({
|
||||
if (propertyAlias === null) {
|
||||
cb = {
|
||||
propertyAlias: null,
|
||||
culture: culture,
|
||||
segment: segment,
|
||||
fieldName: fieldName,
|
||||
callback: callback,
|
||||
id: id
|
||||
});
|
||||
};
|
||||
}
|
||||
else if (propertyAlias !== undefined) {
|
||||
|
||||
callbacks.push({
|
||||
cb = {
|
||||
propertyAlias: propertyAlias,
|
||||
culture: culture,
|
||||
culture: culture,
|
||||
segment: segment,
|
||||
fieldName: fieldName,
|
||||
callback: callback,
|
||||
id: id,
|
||||
matchPrefix: matchValidationPathPrefix
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
callbacks.push(cb);
|
||||
|
||||
function unsubscribeId() {
|
||||
//remove all callbacks for the content field
|
||||
callbacks = _.reject(callbacks, function (item) {
|
||||
@@ -633,9 +625,8 @@ function serverValidationManager($timeout) {
|
||||
});
|
||||
}
|
||||
|
||||
// Now notify the registrations for this callback if we've previously been notified and we're not cleared.
|
||||
// This will happen for dynamically shown editors, like complex editors that load in sub element types.
|
||||
notify();
|
||||
// Notify the new callback
|
||||
notifyCallback(cb);
|
||||
|
||||
//return a function to unsubscribe this subscription by uniqueId
|
||||
return unsubscribeId;
|
||||
@@ -733,7 +724,7 @@ function serverValidationManager($timeout) {
|
||||
|
||||
if (items.length !== count) {
|
||||
// removal was successful, re-notify all subscribers
|
||||
notify();
|
||||
notifyCallbacks();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -757,6 +748,10 @@ function serverValidationManager($timeout) {
|
||||
return undefined;
|
||||
},
|
||||
|
||||
getPropertyErrorsByValidationPath: function (propertyAlias, culture, segment) {
|
||||
return getPropertyErrors(propertyAlias, culture, segment, "", true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name getFieldError
|
||||
|
||||
@@ -27,6 +27,21 @@
|
||||
|
||||
build: function (entityType, guid) {
|
||||
return "umb://" + entityType + "/" + (guid.replace(/-/g, ""));
|
||||
},
|
||||
|
||||
getKey: function (udi) {
|
||||
if (!Utilities.isString(udi)) {
|
||||
throw "udi is not a string";
|
||||
}
|
||||
if (!udi.startsWith("umb://")) {
|
||||
throw "udi does not start with umb://";
|
||||
}
|
||||
var withoutScheme = udi.substr("umb://".length);
|
||||
var withoutHost = withoutScheme.substr(withoutScheme.indexOf("/") + 1).trim();
|
||||
if (withoutHost.length !== 32) {
|
||||
throw "udi is not 32 chars";
|
||||
}
|
||||
return `${withoutHost.substr(0, 8)}-${withoutHost.substr(8, 4)}-${withoutHost.substr(12, 4)}-${withoutHost.substr(16, 4)}-${withoutHost.substr(20)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
data-element="property-{{property.alias}}"
|
||||
ng-repeat="property in group.properties track by property.alias"
|
||||
property="property"
|
||||
element-udi="{{vm.model.udi}}"
|
||||
element-key="{{vm.model.key}}"
|
||||
show-inherit="vm.model.variants.length > 1 && !property.culture && !activeVariant.language.isDefault"
|
||||
inherits-from="defaultVariant.language.name">
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<umb-property property="property"
|
||||
property-alias="{{property.propertyAlias}}"
|
||||
element-udi="{{model.key}}"
|
||||
element-key="{{model.key}}"
|
||||
ng-class="{'umb-nested-content--not-supported': property.notSupported, 'umb-nested-content--mandatory': property.ncMandatory}"
|
||||
data-element="property-{{property.alias}}">
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
describe('serverValidationManager tests', function () {
|
||||
var serverValidationManager;
|
||||
var $rootScope, serverValidationManager, $timeout;
|
||||
|
||||
beforeEach(module('umbraco.services'));
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
$rootScope = $injector.get('$rootScope');
|
||||
$timeout = $injector.get('$timeout');
|
||||
serverValidationManager = $injector.get('serverValidationManager');
|
||||
serverValidationManager.clear();
|
||||
}));
|
||||
@@ -480,7 +482,9 @@
|
||||
allErrors: allErrors
|
||||
};
|
||||
}, null);
|
||||
|
||||
|
||||
|
||||
//act
|
||||
serverValidationManager.addFieldError("Name", "Required");
|
||||
serverValidationManager.addPropertyError("myProperty", null, "value1", "Some value 1", null);
|
||||
@@ -501,7 +505,9 @@
|
||||
var cb2 = function () {
|
||||
};
|
||||
serverValidationManager.subscribe(null, null, "Name", cb1, null);
|
||||
|
||||
serverValidationManager.subscribe(null, null, "Title", cb2, null);
|
||||
|
||||
|
||||
//act
|
||||
serverValidationManager.addFieldError("Name", "Required");
|
||||
@@ -537,6 +543,7 @@
|
||||
};
|
||||
}, null);
|
||||
|
||||
|
||||
serverValidationManager.subscribe("myProperty", null, "", function (isValid, propertyErrors, allErrors) {
|
||||
numCalled++;
|
||||
args2 = {
|
||||
@@ -545,6 +552,9 @@
|
||||
allErrors: allErrors
|
||||
};
|
||||
}, null);
|
||||
|
||||
|
||||
console.log("NOW ADDING ERRORS " + numCalled);
|
||||
|
||||
//act
|
||||
serverValidationManager.addPropertyError("myProperty", null, "value1", "Some value 1", null);
|
||||
@@ -587,6 +597,7 @@
|
||||
allErrors: allErrors
|
||||
};
|
||||
}, null);
|
||||
|
||||
|
||||
serverValidationManager.subscribe(null, "es-ES", null, function (isValid, propertyErrors, allErrors) {
|
||||
numCalled++;
|
||||
@@ -596,6 +607,7 @@
|
||||
allErrors: allErrors
|
||||
};
|
||||
}, null);
|
||||
|
||||
|
||||
//act
|
||||
serverValidationManager.addPropertyError("myProperty", null, "value1", "Some value 1", null);
|
||||
@@ -604,28 +616,30 @@
|
||||
serverValidationManager.addPropertyError("myProperty", "fr-FR", "", "Some value 3", null);
|
||||
|
||||
//assert
|
||||
expect(args1).not.toBeUndefined();
|
||||
expect(args1.isValid).toBe(false);
|
||||
expect(args2.isValid).toBe(true); // no errors registered for this callback
|
||||
|
||||
expect(args2).toBeUndefined();
|
||||
|
||||
expect(numCalled).toEqual(2);
|
||||
expect(numCalled).toEqual(8); // both subscriptions will be called once per addPropertyError
|
||||
});
|
||||
|
||||
it('can subscribe to a property validation path prefix', function () {
|
||||
var numCalled = 0;
|
||||
var callbackA = [];
|
||||
var callbackB = [];
|
||||
|
||||
//arrange
|
||||
serverValidationManager.subscribe("myProperty", null, null, function (isValid, propertyErrors, allErrors) {
|
||||
numCalled++;
|
||||
// since this is matching on prefix, there should be as many property errors as numCalled
|
||||
expect(propertyErrors.length).toEqual(numCalled);
|
||||
callbackA.push(propertyErrors);
|
||||
}, null, true);
|
||||
|
||||
serverValidationManager.subscribe("myProperty/34E3A26C-103D-4A05-AB9D-7E14032309C3/addresses", null, null, function (isValid, propertyErrors, allErrors) {
|
||||
callbackB.push(propertyErrors);
|
||||
}, null, true);
|
||||
|
||||
//act
|
||||
// will match:
|
||||
// will match A:
|
||||
serverValidationManager.addPropertyError("myProperty", null, null, "property error", null);
|
||||
serverValidationManager.addPropertyError("myProperty", null, "value1", "value error", null);
|
||||
// will match A + B
|
||||
serverValidationManager.addPropertyError("myProperty/34E3A26C-103D-4A05-AB9D-7E14032309C3/addresses/FBEAEE8F-4BC9-43EE-8B81-FCA8978850F1/city", null, null, "property error", null);
|
||||
serverValidationManager.addPropertyError("myProperty/34E3A26C-103D-4A05-AB9D-7E14032309C3/addresses/FBEAEE8F-4BC9-43EE-8B81-FCA8978850F1/city", null, "value1", "value error", null);
|
||||
// won't match:
|
||||
@@ -635,7 +649,25 @@
|
||||
serverValidationManager.addPropertyError("otherProperty", null, "value1", "value error", null);
|
||||
|
||||
//assert
|
||||
expect(numCalled).toEqual(4);
|
||||
|
||||
// both will be called each time addPropertyError is called
|
||||
expect(callbackA.length).toEqual(8);
|
||||
expect(callbackB.length).toEqual(8);
|
||||
expect(callbackA[callbackA.length - 1].length).toEqual(4); // 4 errors for A
|
||||
expect(callbackB[callbackB.length - 1].length).toEqual(2); // 2 errors for B
|
||||
|
||||
// clear the data and notify
|
||||
callbackA = [];
|
||||
callbackB = [];
|
||||
|
||||
serverValidationManager.notify();
|
||||
$timeout.flush();
|
||||
|
||||
expect(callbackA.length).toEqual(1);
|
||||
expect(callbackB.length).toEqual(1);
|
||||
expect(callbackA[0].length).toEqual(4); // 4 errors for A
|
||||
expect(callbackB[0].length).toEqual(2); // 2 errors for B
|
||||
|
||||
});
|
||||
|
||||
// TODO: Finish testing the rest!
|
||||
|
||||
Reference in New Issue
Block a user