enhances valServerMatch to be more flexible and allow for different validation keys which we can then use for matching on settings or content and have different styles for validators

This commit is contained in:
Shannon
2020-07-28 11:43:53 +10:00
parent 5aba8190ae
commit 768b31e091
4 changed files with 73 additions and 35 deletions

View File

@@ -1,5 +1,17 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:valServerMatch
* @restrict A
* @description A custom validator applied to a form/ng-form within an umbProperty that validates server side validation data
* contained within the serverValidationManager. The data can be matched on "exact", "prefix", "suffix" or "contains" matches against
* a property validation key. The attribute value can be in multiple value types:
* - STRING = The property validation key to have an exact match on. If matched, then the form will have a valServerMatch validator applied.
* - OBJECT = A dictionary where the key is the match type: "contains", "prefix", "suffix" and the value is either:
* - ARRAY = A list of property validation keys to match on. If any are matched then the form will have a valServerMatch validator applied.
* - OBJECT = A dictionary where the key is the validator error name applied to the form and the value is the STRING of the property validation key to match on
**/
function valServerMatch(serverValidationManager) {
return {
require: ['form', '^^umbProperty', '?^^umbVariantContent'],
restrict: "A",
@@ -40,48 +52,63 @@ function valServerMatch(serverValidationManager) {
var unsubscribe = [];
//subscribe to the server validation changes
function serverValidationManagerCallback(isValid, propertyErrors, allErrors) {
if (!isValid) {
formCtrl.$setValidity('valServerMatch', false);
}
else {
formCtrl.$setValidity('valServerMatch', true);
function bindCallback(validationKey, matchVal, matchType) {
if (Utilities.isString(matchVal)) {
matchVal = [matchVal]; // normalize to an array since the value can also natively be an array
}
// match for each string in the array
matchVal.forEach(m => {
unsubscribe.push(serverValidationManager.subscribe(
m,
currentCulture,
"",
// the callback
function (isValid, propertyErrors, allErrors) {
if (!isValid) {
formCtrl.$setValidity(validationKey, false);
}
else {
formCtrl.$setValidity(validationKey, true);
}
},
currentSegment,
matchType ? { matchType: matchType } : null // specify the match type
));
});
}
if (Utilities.isObject(scope.valServerMatch)) {
var allowedKeys = ["contains", "prefix", "suffix"];
Object.keys(scope.valServerMatch).forEach(k => {
if (allowedKeys.indexOf(k) === -1) {
Object.keys(scope.valServerMatch).forEach(matchType => {
if (allowedKeys.indexOf(matchType) === -1) {
throw "valServerMatch dictionary keys must be one of " + allowedKeys.join();
}
var matchVal = scope.valServerMatch[k];
if (Utilities.isString(matchVal)) {
matchVal = [matchVal]; // change to an array since the value can also natively be an array
}
var matchVal = scope.valServerMatch[matchType];
// match for each string in the array
matchVal.forEach(m => {
unsubscribe.push(serverValidationManager.subscribe(
m,
currentCulture,
"",
serverValidationManagerCallback,
currentSegment,
{ matchType: k } // specify the match type
));
})
if (Utilities.isObject(matchVal)) {
// as an object, the key will be the validation error instead of the default "valServerMatch"
Object.keys(matchVal).forEach(valKey => {
// matchVal[valKey] can be an ARRAY or a STRING
bindCallback(valKey, matchVal[valKey], matchType);
});
}
else {
// matchVal can be an ARRAY or a STRING
bindCallback("valServerMatch", matchVal, matchType);
}
});
}
else if (Utilities.isString(scope.valServerMatch)) {
unsubscribe.push(serverValidationManager.subscribe(
scope.valServerMatch,
currentCulture,
"",
serverValidationManagerCallback,
currentSegment));
// a STRING match which will be an exact match on the string supplied as the property validation key
bindCallback("valServerMatch", scope.valServerMatch, null);
}
else {
throw "valServerMatch value must be a string or a dictionary";

View File

@@ -23,13 +23,17 @@
> .umb-block-list__block--actions {
opacity: 0;
transition: opacity 120ms;
.--error {
color: @formErrorBorder !important;
}
}
&:hover,
&:focus,
&:focus-within,
&.--active {
> .umb-block-list__block--actions {
opacity: 1;
}

View File

@@ -1,4 +1,4 @@
<ng-form name="vm.blockRowForm" val-server-match="{ 'contains' : [ vm.layout.$block.content.key, vm.layout.$block.settings.key] }">
<ng-form name="vm.blockRowForm" val-server-match="{ 'contains' : { 'valServerMatchContent': vm.layout.$block.content.key, 'valServerMatchSettings': vm.layout.$block.settings.key } }">
<div class="umb-block-list__block" ng-class="{'--active':vm.layout.$block.active}">
<umb-block-list-block stylesheet="{{::vm.layout.$block.config.stylesheet}}"
@@ -13,19 +13,23 @@
<div class="umb-block-list__block--actions">
<button type="button" class="btn-reset umb-outline action --settings" localize="title" title="actions_editSettings"
ng-click="vm.blockEditorApi.openSettingsForBlock(vm.layout.$block, vm.index, vm.blockRowForm);"
ng-class="{ '--error': vm.blockRowForm.$error.valServerMatchSettings && vm.valFormManager.isShowingValidation() }"
ng-if="vm.layout.$block.showSettings === true">
<i class="icon icon-settings" aria-hidden="true"></i>
<span class="sr-only">
<localize key="general_settings">Settings</localize>
</span>
</button>
<button type="button" class="btn-reset umb-outline action --copy" localize="title" title="actions_copy" ng-click="vm.blockEditorApi.copyBlock(vm.layout.$block);" ng-if="vm.layout.$block.showCopy === true">
<button type="button" class="btn-reset umb-outline action --copy" localize="title" title="actions_copy"
ng-click="vm.blockEditorApi.copyBlock(vm.layout.$block);"
ng-if="vm.layout.$block.showCopy === true">
<i class="icon icon-documents" aria-hidden="true"></i>
<span class="sr-only">
<localize key="general_copy">Copy</localize>
</span>
</button>
<button type="button" class="btn-reset umb-outline action --delete" localize="title" title="actions_delete" ng-click="vm.blockEditorApi.requestDeleteBlock(vm.layout.$block);">
<button type="button" class="btn-reset umb-outline action --delete" localize="title" title="actions_delete"
ng-click="vm.blockEditorApi.requestDeleteBlock(vm.layout.$block);">
<i class="icon icon-trash" aria-hidden="true"></i>
<span class="sr-only">
<localize key="general_delete">Delete</localize>

View File

@@ -18,6 +18,9 @@
blockEditorApi: "<",
layout: "<",
index: "<"
},
require: {
valFormManager: "^^valFormManager"
}
}
);