diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypegroup.component.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypegroup.component.js index e3023e2170..5b9c9ab0a1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypegroup.component.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypegroup.component.js @@ -9,21 +9,12 @@ const vm = this; - vm.$onInit = onInit; - vm.updateName = updateName; vm.removeGroup = removeGroup; vm.whenNameFocus = whenNameFocus; vm.whenFocus = whenFocus; vm.changeSortOrderValue = changeSortOrderValue; - function onInit() { - // we need a group name for the validation and angular doesn't allow dashes in form name. - // this is a workaround to make it work - const identifier = vm.group.key.replaceAll('-', ''); - vm.formName = `groupForm${identifier}`; - } - function updateName (group) { if (vm.onUpdateName) { vm.onUpdateName({ group }); @@ -66,10 +57,11 @@ allowRemove: '<', onRemove: '&', sorting: '<', - valServerFieldName: '@', onNameFocus: '&', onFocus: '&', - onChangeSortOrderValue: '&' + onChangeSortOrderValue: '&', + valServerFieldName: '@', + valTabAlias: "@" }, controller: umbContentTypeGroupController }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypeproperty.component.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypeproperty.component.js index 12b6074dc0..8f27332ec2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypeproperty.component.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/contenttype/umbcontenttypeproperty.component.js @@ -40,9 +40,10 @@ sortable: '<', onEdit: '&', onRemove: '&', + onChangeSortOrderValue: '&', valServerFieldAlias: '@', valServerFieldLabel: '@', - onChangeSortOrderValue: '&' + valTabAlias: '@' }, controllerAs: 'vm', controller: umbContentTypePropertyController diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js index 1db2f88a9f..f288e50468 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js @@ -3,7 +3,7 @@ function GroupsBuilderDirective(contentTypeHelper, contentTypeResource, mediaTypeResource, dataTypeHelper, dataTypeResource, $filter, iconHelper, $q, $timeout, notificationsService, - localizationService, editorService, eventsService, overlayService) { + localizationService, editorService, eventsService, overlayService, contentEditingHelper) { function link(scope, el, attr, ctrl) { @@ -26,6 +26,7 @@ scope.genericTab = { key: null, name: "Generic", + alias: contentEditingHelper.genericTabAlias, parentKey: null, type: TYPE_TAB, sortOrder: 0, @@ -41,6 +42,10 @@ tab.indexInGroups = newValue.findIndex(group => group.key === tab.key); }); + newValue.forEach(group => { + group.validationAlias = contentEditingHelper.generateTabValidationAlias(group, newValue); + }); + checkGenericTabVisibility(); if (!scope.openTabKey && scope.hasGenericTab) { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valgroupsintab.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valgroupsintab.directive.js deleted file mode 100644 index 34923d6fef..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valgroupsintab.directive.js +++ /dev/null @@ -1,55 +0,0 @@ -(function () { - 'use strict'; - - function valGroupsInTabDirective(angularHelper) { - function link(scope, el, attrs, ctrl) { - const valFormManager = ctrl[1]; - const formCtrl = ctrl[0]; - - if (!valFormManager) { - return; - } - - // valformmanager onValidationStatusChanged only emit updates when the parent form status changes. - // In this case we need to know the status for all sub forms so we can update each tab validation status correctly based on the child group form states. - // the code finds the child group form for a given tab and if any of those group forms are invalid the tab will be flag with an error. - scope.$watch(() => angularHelper.countAllFormErrors(formCtrl), () => { - update(); - }); - - function update () { - const { tab, groups } = scope.$eval(attrs.valGroupsInTab); - - if (!tab && !groups) { - tab.hasError = false; - return; - } - - const tabGroups = []; - const tabGroupsIdentifiers = groups.filter(group => group.parentKey === tab.key).map(group => group.key.replaceAll('-', '')); - - for (const [key, value] of Object.entries(formCtrl)) { - if (key.startsWith('groupForm')) { - const groupIdentifier = key.replace('groupForm', ''); - if (groupIdentifier && tabGroupsIdentifiers.indexOf(groupIdentifier) !== -1) { - tabGroups.push(value); - } - } - } - - tab.hasError = tabGroups.filter(group => group.$invalid).length > 0; - } - } - - var directive = { - require: ['?^^form', '?^^valFormManager'], - restrict: "A", - link: link - }; - - return directive; - } - - angular.module('umbraco.directives').directive('valGroupsInTab', valGroupsInTabDirective); - -})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js index 057d2ec1ac..d3ed7a2f9d 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js @@ -12,14 +12,21 @@ function valTab($timeout) { restrict: "A", link: function (scope, element, attr, ctrs) { + var evts = []; var form = ctrs[0]; - var tabAlias = scope.tab.alias; + var tab = scope.$eval(attr.valTab) || scope.tab; + + if (!tab) { + return; + } + + var tabAlias = tab.alias || tab.key; let closestEditor = element.closest(".blockelement-inlineblock-editor"); closestEditor = closestEditor.length === 0 ? element.closest(".umb-editor-sub-view") : closestEditor; closestEditor = closestEditor.length === 0 ? element.closest(".umb-editor") : closestEditor; - scope.tabHasError = false; + setSuccess(); function setValidity (form) { if (!form.$valid) { @@ -27,23 +34,50 @@ function valTab($timeout) { //check if the validation messages are contained inside of this tabs if (tabContent.find(".ng-invalid").length > 0) { - scope.tabHasError = true; + setError(); } else { - scope.tabHasError = false; + setSuccess(); } } else { - scope.tabHasError = false; + setSuccess(); } } + function setError () { + scope.tabHasError = true; + tab.hasError = true; + } + + function setSuccess () { + scope.tabHasError = false; + tab.hasError = false; + } + + function subscribe () { + for (let control of form.$$controls) { + var unbind = scope.$watch(() => control.$invalid, function () { + setValidity(form); + }); + + evts.push(unbind); + } + } + + function unsubscribe () { + evts.forEach(event => event()); + } + // we need to watch validation state on individual controls so we can update specific tabs accordingly $timeout(() => { - for (let control of form.$$controls) { - scope.$watch(() => control.$invalid, function () { - setValidity(form); - }); - } + scope.$watchCollection(() => form.$$controls, function (newValue) { + unsubscribe(); + subscribe(); + }); + }); + + scope.$on('$destroy', function () { + unsubscribe(); }); } }; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 219a7f92ad..cc2d2153fe 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -183,19 +183,20 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt genericTabAlias: "_umb_genericTab", generateTabValidationAlias: function (group, groups) { + const prefix = "tab-content-"; let validationAlias = this.genericTabAlias; if (group.parentKey) { const parentGroup = groups.find(tab => tab.key === group.parentKey); - validationAlias = parentGroup.alias; + validationAlias = parentGroup.alias || parentGroup.key; } // tabs should use their own alias so direct properties will trigger the right tab if (group.type === 1) { - validationAlias = group.alias; + validationAlias = group.alias || group.key; } - return validationAlias; + return prefix + validationAlias; }, registerGenericTab: function (groups) { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html index db60df6baf..49f48875aa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-tabbed-content.html @@ -6,7 +6,7 @@ - + {{ group.label }} -
+
- -
+
- -
- - + +
+ + -
-
{{groupNameForm.groupName.errorMsg}}
-
-
+
+
{{groupNameForm.groupName.errorMsg}}
+
- - -
- - : {{ vm.group.inheritedFromName }} - - - , -
+ - -
- - - -
-
-
-
-
-
- -
- -
+
+ + : {{ vm.group.inheritedFromName }} + + + , +
-
- + +
+ + + +
+
+
+
+
+
+ +
+
- +
+ +
+ +
\ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html index 4834cbd557..5724aa4e2e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-property.html @@ -1,7 +1,7 @@
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html index 2be8c6286a..9f90f6e007 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/contenttype/umb-content-type-tab.html @@ -1,4 +1,4 @@ -
+
: {{ vm.tab.inheritedFromName }} diff --git a/src/Umbraco.Web.UI.Client/src/views/components/elementeditor/umb-element-editor-content.component.html b/src/Umbraco.Web.UI.Client/src/views/components/elementeditor/umb-element-editor-content.component.html index 461c3dceaa..e1668f4938 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/elementeditor/umb-element-editor-content.component.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/elementeditor/umb-element-editor-content.component.html @@ -6,7 +6,7 @@ - + {{ group.label }}
-
+
-
  • +
  • + val-tab-alias="{{group.validationAlias}}">
    • @@ -136,9 +137,10 @@ sortable="sortingMode" on-edit="editPropertyTypeSettings(property)" on-remove="deleteProperty(group.properties, property)" + on-change-sort-order-value="onChangePropertySortOrderValue(group)" val-server-field-alias="{{'Groups[' + groupIndex + '].Properties[' + propertyIndex + '].Alias'}}" val-server-field-label="{{'Groups[' + groupIndex + '].Properties[' + propertyIndex + '].Label'}}" - on-change-sort-order-value="onChangePropertySortOrderValue(group)"> + val-tab-alias="{{group.validationAlias}}">