Add valServerMatch which we now use to highlight block rows if they have errors.

This commit is contained in:
Shannon
2020-07-15 16:49:54 +10:00
parent f4d8d0e28e
commit b32d92ed07
7 changed files with 121 additions and 21 deletions

View File

@@ -288,7 +288,7 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
"",
serverValidationManagerCallback,
currentSegment,
{ matchPrefix: true } // match property validation path prefix
{ matchType: "suffix" } // match property validation path prefix
));
}
@@ -298,9 +298,7 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
//when the scope is disposed we need to unsubscribe
scope.$on('$destroy', function () {
stopWatch();
for (var u in unsubscribe) {
unsubscribe[u]();
}
unsubscribe.forEach(u => u());
});
onInit();

View File

@@ -13,14 +13,14 @@ function valServer(serverValidationManager) {
link: function (scope, element, attr, ctrls) {
var modelCtrl = ctrls[0];
var umbPropCtrl = ctrls.length > 1 ? ctrls[1] : null;
var umbPropCtrl = ctrls[1];
if (!umbPropCtrl) {
//we cannot proceed, this validator will be disabled
return;
}
// optional reference to the varaint-content-controller, needed to avoid validation when the field is invariant on non-default languages.
var umbVariantCtrl = ctrls.length > 2 ? ctrls[2] : null;
var umbVariantCtrl = ctrls[2];
var currentProperty = umbPropCtrl.property;
var currentCulture = currentProperty.culture;
@@ -121,9 +121,7 @@ function valServer(serverValidationManager) {
scope.$on('$destroy', function () {
stopWatch();
for (var u in unsubscribe) {
unsubscribe[u]();
}
unsubscribe.forEach(u => u());
});
}
};

View File

@@ -0,0 +1,89 @@
function valServerMatch(serverValidationManager) {
return {
require: ['form', '^^umbProperty', '?^^umbVariantContent'],
restrict: "A",
scope: {
valServerMatch: "="
},
link: function (scope, element, attr, ctrls) {
var formCtrl = ctrls[0];
var umbPropCtrl = ctrls[1];
if (!umbPropCtrl) {
//we cannot proceed, this validator will be disabled
return;
}
// optional reference to the varaint-content-controller, needed to avoid validation when the field is invariant on non-default languages.
var umbVariantCtrl = ctrls[2];
var currentProperty = umbPropCtrl.property;
var currentCulture = currentProperty.culture;
var currentSegment = currentProperty.segment;
if (umbVariantCtrl) {
//if we are inside of an umbVariantContent directive
var currentVariant = umbVariantCtrl.editor.content;
// Lets check if we have variants and we are on the default language then ...
if (umbVariantCtrl.content.variants.length > 1 && (!currentVariant.language || !currentVariant.language.isDefault) && !currentCulture && !currentSegment && !currentProperty.unlockInvariantValue) {
//This property is locked cause its a invariant property shown on a non-default language.
//Therefor do not validate this field.
return;
}
}
// 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";
var unsubscribe = [];
//subscribe to the server validation changes
function serverValidationManagerCallback(isValid, propertyErrors, allErrors) {
if (!isValid) {
formCtrl.$setValidity('valServerMatch', false, formCtrl);
}
else {
formCtrl.$setValidity('valServerMatch', true, formCtrl);
}
}
if (Utilities.isObject(scope.valServerMatch)) {
var allowedKeys = ["contains", "prefix", "suffix"];
Object.keys(scope.valServerMatch).forEach(k => {
if (allowedKeys.indexOf(k) === -1) {
throw "valServerMatch dictionary keys must be one of " + allowedKeys.join();
}
unsubscribe.push(serverValidationManager.subscribe(
scope.valServerMatch[k],
currentCulture,
"",
serverValidationManagerCallback,
currentSegment,
{ matchType: k } // specify the match type
));
});
}
else if (Utilities.isString(scope.valServerMatch)) {
unsubscribe.push(serverValidationManager.subscribe(
scope.valServerMatch,
currentCulture,
"",
serverValidationManagerCallback,
currentSegment));
}
else {
throw "valServerMatch value must be a string or a dictionary";
}
scope.$on('$destroy', function () {
unsubscribe.forEach(u => u());
});
}
};
}
angular.module('umbraco.directives.validation').directive("valServerMatch", valServerMatch);

View File

@@ -129,9 +129,9 @@
var prop = tab.properties[p];
// Watch value of property since this is the only value we want to keep synced.
// Do notice that it is not performing a deep watch, meaning that we are only watching primatives and changes directly to the object of property-value.
// But we like to sync non-primative values as well! Yes, and this does happen, just not through this code, but through the nature of JavaScript.
// Non-primative values act as references to the same data and are therefor synced.
// Do notice that it is not performing a deep watch, meaning that we are only watching primitive and changes directly to the object of property-value.
// But we like to sync non-primitive values as well! Yes, and this does happen, just not through this code, but through the nature of JavaScript.
// Non-primitive values act as references to the same data and are therefor synced.
blockObject.__watchers.push(isolatedScope.$watch("blockObjects._" + blockObject.key + "." + field + ".variants[0].tabs[" + t + "].properties[" + p + "].value", watcherCreator(blockObject, prop)));
// We also like to watch our data model to be able to capture changes coming from other places.

View File

@@ -63,8 +63,20 @@ angular.module("umbraco")
}
}
vm.close = function() {
vm.close = function () {
if (vm.model && vm.model.close) {
// TODO: At this stage there could very well have been server errors that have been cleared
// but if we 'close' we are basically cancelling the value changes which means we'd want to cancel
// all of the server errors just cleared. It would be possible to do that but also quite annoying.
// The rudimentary way would be to:
// * Track all cleared server errors here by subscribing to the prefix validation of controls contained here
// * If this is closed, re-add all of those server validation errors
// A more robust way to do this would be to:
// * Add functionality to the serverValidationManager whereby we can remove validation errors and it will
// maintain a copy of the original errors
// * It would have a 'commit' method to commit the removed errors - which we would call in the formHelper.submitForm when it's successful
// * It would have a 'rollback' method to reset the removed errors - which we would call here
// TODO: check if content/settings has changed and ask user if they are sure.
vm.model.close(vm.model);
}

View File

@@ -1,7 +1,10 @@
<button type="button" class="btn-reset umb-outline blockelement-labelblock-editor blockelement__draggable-element"
ng-click="api.editBlock(block, block.hideContentInOverlay, index)"
ng-focus="block.focus"
ng-class="{'--active':block.active}">
<i class="icon {{block.content.icon}}"></i>
<span>{{block.label}}</span>
</button>
<ng-form name="blockRowForm" val-server-match="{ 'contains' : block.content.key }">
<button type="button" class="btn-reset umb-outline blockelement-labelblock-editor blockelement__draggable-element"
ng-click="api.editBlock(block, block.hideContentInOverlay, index)"
ng-focus="block.focus"
ng-class="{ '--active': block.active || blockRowForm.$invalid }"
val-server-property-class="">
<i class="icon {{block.content.icon}}"></i>
<span>{{block.label}}</span>
</button>
</ng-form>

View File

@@ -119,7 +119,7 @@
});
it('getBlockObject syncs primative values', function (done) {
it('getBlockObject syncs primitive values', function (done) {
var propertyModel = angular.copy(propertyModelMock);