diff --git a/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs b/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs index 7990998d9e..e40ae002d6 100644 --- a/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/RequiredValueValidator.cs @@ -15,11 +15,11 @@ namespace Umbraco.Core.PropertyEditors if (value == null) { - yield return new ValidationResult("Value cannot be null"); + yield return new ValidationResult("Value cannot be null", new[] { "value" }); } if (value.IsNullOrWhiteSpace()) { - yield return new ValidationResult("Value cannot be empty"); + yield return new ValidationResult("Value cannot be empty", new[] { "value" }); } } } 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 bf480be7a3..db9e05dc22 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 @@ -38,14 +38,10 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser * @description * re-binds all changed property values to the origContent object from the newContent object and returns an array of changed properties. */ - reBindChangedProperties: function (origContent, newContent) { + reBindChangedProperties: function (allOrigProps, allNewProps) { var changed = []; - //get a list of properties since they are contained in tabs - var allOrigProps = this.getAllProps(origContent); - var allNewProps = this.getAllProps(newContent); - function getNewProp(alias) { if (alias.startsWith("_umb_")) { return null; @@ -78,10 +74,8 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser * It's worth noting that when a 403 occurs, the data is still saved just never published, though this depends on if the entity is a new * entity and whether or not the data fulfils the absolute basic requirements like having a mandatory Name. */ - handleValidationErrors: function (content, modelState) { - //get a list of properties since they are contained in tabs - var allProps = this.getAllProps(content); - + handleValidationErrors: function (allProps, modelState) { + //find the content property for the current error, for use in the loop below function findContentProp(props, propAlias) { return _.find(props, function (item) { @@ -132,21 +126,36 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser * @description * A function to handle what happens when we have validation issues from the server side */ - handleSaveError: function (err, scope) { + handleSaveError: function (args) { + + if (!args.err) { + throw "args.err cannot be null"; + } + if (!args.allNewProps && !angular.isArray(args.allNewProps)) { + throw "args.allNewProps must be a valid array"; + } + if (!args.allOrigProps && !angular.isArray(args.allOrigProps)) { + throw "args.allOrigProps must be a valid array"; + } + //When the status is a 403 status, we have validation errors. //Otherwise the error is probably due to invalid data (i.e. someone mucking around with the ids or something). //Or, some strange server error - if (err.status === 403) { + if (args.err.status === 403) { //now we need to look through all the validation errors - if (err.data && (err.data.modelState)) { + if (args.err.data && (args.err.data.ModelState)) { + + this.handleValidationErrors(args.allNewProps, args.err.data.ModelState); - this.handleValidationErrors(err.data, err.data.modelState); - - if (!this.redirectToCreatedContent(err.data.id, err.data.modelState)) { + if (!this.redirectToCreatedContent(args.err.data.id, args.err.data.ModelState)) { //we are not redirecting because this is not new content, it is existing content. In this case // we need to detect what properties have changed and re-bind them with the server data. Then we need // to re-bind any server validation errors after the digest takes place. - this.reBindChangedProperties(scope.content, err.data); + + if (args.rebindCallback && angular.isFunction(args.rebindCallback)) { + args.rebindCallback(); + } + serverValidationManager.executeAndClearAllSubscriptions(); } @@ -154,11 +163,11 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser return true; } else { - dialogService.ysodDialog(err); + dialogService.ysodDialog(args.err); } } else { - dialogService.ysodDialog(err); + dialogService.ysodDialog(args.err); } return false; @@ -166,7 +175,7 @@ function contentEditingHelper($location, $routeParams, notificationsService, ser /** * @ngdoc function - * @name umbraco.services.contentEditingHelper#handleSaveError + * @name umbraco.services.contentEditingHelper#handleSuccessfulSave * @methodOf umbraco.services.contentEditingHelper * @function * diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index a260ce904e..9b52da35ad 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -85,7 +85,7 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ * In both of the above, the successCallback must accept these parameters: data, status, headers, config * If using the errorCallback it must accept these parameters: data, status, headers, config * The success callback must return the data which will be resolved by the deferred object. - * The error callback must return an object containing: {errorMsg: errorMessage, data: originalData } + * The error callback must return an object containing: {errorMsg: errorMessage, data: originalData, status: status } */ resourcePromise: function (httpPromise, opts) { var deferred = $q.defer(); @@ -101,7 +101,8 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ return { //NOTE: the default error message here should never be used based on the above docs! errorMsg: (angular.isString(opts) ? opts : 'An error occurred!'), - data: data + data: data, + status: status }; } @@ -137,7 +138,8 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ //return an error object including the error message for UI deferred.reject({ errorMsg: result.errorMsg, - data: result.data + data: result.data, + status: result.status }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js index 8358dea7b8..7e290796dc 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.edit.controller.js @@ -61,11 +61,22 @@ function ContentEditController($scope, $routeParams, $location, contentResource, contentEditingHelper.handleSuccessfulSave({ scope: $scope, newContent: data, - rebindCallback: contentEditingHelper.reBindChangedProperties(scope.content, data) + rebindCallback: contentEditingHelper.reBindChangedProperties( + contentEditingHelper.getAllProps($scope.content), + contentEditingHelper.getAllProps(data)) }); - }, function (err) { - contentEditingHelper.handleSaveError(err, $scope); + }, function (err) { + + var allNewProps = contentEditingHelper.getAllProps(err.data); + var allOrigProps = contentEditingHelper.getAllProps($scope.content); + + contentEditingHelper.handleSaveError({ + err: err, + allNewProps: allNewProps, + allOrigProps: contentEditingHelper.getAllProps($scope.content), + rebindCallback: contentEditingHelper.reBindChangedProperties(allOrigProps, allNewProps) + }); }); }; @@ -89,7 +100,11 @@ function ContentEditController($scope, $routeParams, $location, contentResource, }); }, function (err) { - contentEditingHelper.handleSaveError(err, $scope); + contentEditingHelper.handleSaveError({ + err: err, + allNewProps: contentEditingHelper.getAllProps(err.data), + allOrigProps: contentEditingHelper.getAllProps($scope.content) + }); }); }; diff --git a/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js index 544a9133b8..72e52d835c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/datatype/datatype.edit.controller.js @@ -102,7 +102,17 @@ function DataTypeEditController($scope, $routeParams, $location, dataTypeResourc }); }, function (err) { - contentEditingHelper.handleSaveError(err, $scope); + + //NOTE: in the case of data type values we are setting the orig/new props + // to be the same thing since that only really matters for content/media. + contentEditingHelper.handleSaveError({ + err: err, + allNewProps: $scope.preValues, + allOrigProps: $scope.preValues, + rebindCallback: function () { + createPreValueProps(err.data.preValues); + } + }); }); }; diff --git a/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js index aa16731fde..088d0ee4a5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js @@ -59,11 +59,22 @@ function mediaEditController($scope, $routeParams, mediaResource, notificationsS contentEditingHelper.handleSuccessfulSave({ scope: $scope, newContent: data, - rebindCallback: contentEditingHelper.reBindChangedProperties(scope.content, data) + rebindCallback: contentEditingHelper.reBindChangedProperties( + contentEditingHelper.getAllProps($scope.content), + contentEditingHelper.getAllProps(data)) }); }, function (err) { - contentEditingHelper.handleSaveError(err, $scope); + + var allNewProps = contentEditingHelper.getAllProps(err.data); + var allOrigProps = contentEditingHelper.getAllProps($scope.content); + + contentEditingHelper.handleSaveError({ + err: err, + allNewProps: allNewProps, + allOrigProps: contentEditingHelper.getAllProps($scope.content), + rebindCallback: contentEditingHelper.reBindChangedProperties(allOrigProps, allNewProps) + }); }); }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/requiredfield.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/requiredfield.html index 79b44ced00..5012926855 100644 --- a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/requiredfield.html +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/requiredfield.html @@ -1,8 +1,8 @@