diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js
index 26164baccb..b9d633b3d8 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbGenerateAlias.directive.js
@@ -7,7 +7,8 @@ angular.module("umbraco.directives")
scope: {
alias: '=',
aliasFrom: '=',
- enableLock: '=?'
+ enableLock: '=?',
+ serverValidationField: '@'
},
link: function (scope, element, attrs, ctrl) {
@@ -32,7 +33,7 @@ angular.module("umbraco.directives")
generateAliasTimeout = $timeout(function () {
updateAlias = true;
entityResource.getSafeAlias(value, true).then(function (safeAlias) {
- if(updateAlias) {
+ if (updateAlias) {
scope.alias = safeAlias.alias;
}
});
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umblockedfield.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umblockedfield.directive.js
index 04fde87de5..a23515ab83 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umblockedfield.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umblockedfield.directive.js
@@ -11,7 +11,17 @@
function LockedFieldDirective($timeout, localizationService) {
- function link(scope, el, attr, ngModel) {
+ function link(scope, el, attr, ngModelCtrl) {
+
+ //watch the ngModel so we can manually update the textbox view value when it changes
+ // this ensures that the normal flow (i.e. a user editing the text box) occurs so that
+ // the parsers, validators and viewchangelisteners execute
+ scope.$watch("ngModel", function (newValue, oldValue) {
+ if (newValue !== oldValue) {
+ scope.lockedFieldForm.lockedField.$setViewValue(newValue);
+ scope.lockedFieldForm.lockedField.$render();
+ }
+ });
var input = el.find('.umb-locked-field__input');
@@ -79,7 +89,7 @@
replace: true,
templateUrl: 'views/components/umb-locked-field.html',
scope: {
- model: '=ngModel',
+ ngModel: "=",
locked: "=?",
placeholderText: "=?",
regexValidation: "=?",
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 d21f297a91..4a690bf0c5 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
@@ -46,6 +46,8 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
throw "args.saveMethod is not defined";
}
+ var redirectOnFailure = args.redirectOnFailure !== undefined ? args.redirectOnFailure : true;
+
var self = this;
//we will use the default one for content if not specified
@@ -75,7 +77,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
}, function (err) {
self.handleSaveError({
- redirectOnFailure: true,
+ redirectOnFailure: redirectOnFailure,
err: err,
rebindCallback: function() {
rebindCallback.apply(self, [args.content, err.data]);
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html
index 5955241fb9..a6e2c4fefd 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/editor/umb-editor-header.html
@@ -25,7 +25,12 @@
{{ name }}
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-generate-alias.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-generate-alias.html
index d68b1cc104..69327474d6 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/umb-generate-alias.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-generate-alias.html
@@ -4,7 +4,9 @@
+ placeholder-text="placeholderText"
+ server-validation-field="{{serverValidationField}}">
+
\ No newline at end of file
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-locked-field.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-locked-field.html
index dca8a01ef8..36f3d43dce 100644
--- a/src/Umbraco.Web.UI.Client/src/views/components/umb-locked-field.html
+++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-locked-field.html
@@ -1,4 +1,4 @@
-
+
@@ -13,7 +13,7 @@
+ title="{{inputModel}}" />
diff --git a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js
index 641ac1c954..abd6b0fdd2 100644
--- a/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/documenttypes/edit.controller.js
@@ -155,6 +155,10 @@
saveMethod: contentTypeResource.save,
scope: $scope,
content: vm.contentType,
+ //We do not redirect on failure for doc types - this is because it is not possible to actually save the doc
+ // type when server side validation fails - as opposed to content where we are capable of saving the content
+ // item if server side validation fails
+ redirectOnFailure: false,
// we need to rebind... the IDs that have been created!
rebindCallback: function (origContentType, savedContentType) {
vm.contentType.id = savedContentType.id;
diff --git a/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js
index bcfb826811..49133e8713 100644
--- a/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js
@@ -136,6 +136,10 @@
saveMethod: mediaTypeResource.save,
scope: $scope,
content: vm.contentType,
+ //We do not redirect on failure for doc types - this is because it is not possible to actually save the doc
+ // type when server side validation fails - as opposed to content where we are capable of saving the content
+ // item if server side validation fails
+ redirectOnFailure: false,
//no-op for rebind callback... we don't really need to rebind for content types
rebindCallback: angular.noop
}).then(function (data) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/membertypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/membertypes/edit.controller.js
index 2999eb6919..3a1d91d2f0 100644
--- a/src/Umbraco.Web.UI.Client/src/views/membertypes/edit.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/membertypes/edit.controller.js
@@ -90,6 +90,10 @@
saveMethod: memberTypeResource.save,
scope: $scope,
content: vm.contentType,
+ //We do not redirect on failure for doc types - this is because it is not possible to actually save the doc
+ // type when server side validation fails - as opposed to content where we are capable of saving the content
+ // item if server side validation fails
+ redirectOnFailure: false,
//no-op for rebind callback... we don't really need to rebind for content types
rebindCallback: angular.noop
}).then(function (data) {
diff --git a/src/Umbraco.Web/Editors/ContentTypeController.cs b/src/Umbraco.Web/Editors/ContentTypeController.cs
index 4622fee1b5..de072331aa 100644
--- a/src/Umbraco.Web/Editors/ContentTypeController.cs
+++ b/src/Umbraco.Web/Editors/ContentTypeController.cs
@@ -147,10 +147,11 @@ namespace Umbraco.Web.Editors
public ContentTypeDisplay PostSave(ContentTypeSave contentTypeSave)
{
var savedCt = PerformPostSave(
- contentTypeSave: contentTypeSave,
- getContentType: i => Services.ContentTypeService.GetContentType(i),
- saveContentType: type => Services.ContentTypeService.Save(type),
- beforeCreateNew: ctSave =>
+ contentTypeSave: contentTypeSave,
+ getContentType: i => Services.ContentTypeService.GetContentType(i),
+ getContentTypeByAlias: alias => Services.ContentTypeService.GetContentType(alias),
+ saveContentType: type => Services.ContentTypeService.Save(type),
+ beforeCreateNew: ctSave =>
{
//create a default template if it doesnt exist -but only if default template is == to the content type
//TODO: Is this really what we want? What if we don't want any template assigned at all ?
diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
index 975154e6e8..f90c2c3e6b 100644
--- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
+++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs
@@ -155,6 +155,7 @@ namespace Umbraco.Web.Editors
protected TContentType PerformPostSave(
ContentTypeSave contentTypeSave,
Func getContentType,
+ Func getContentTypeByAlias,
Action saveContentType,
bool validateComposition = true,
Action beforeCreateNew = null)
@@ -163,6 +164,13 @@ namespace Umbraco.Web.Editors
{
var ctId = Convert.ToInt32(contentTypeSave.Id);
+ //Validate that there's no other ct with the same name
+ var exists = getContentTypeByAlias(contentTypeSave.Alias);
+ if (exists != null)
+ {
+ ModelState.AddModelError("Alias", "A content type with this alias already exists");
+ }
+
if (ModelState.IsValid == false)
{
var ct = getContentType(ctId);
diff --git a/src/Umbraco.Web/Editors/MediaTypeController.cs b/src/Umbraco.Web/Editors/MediaTypeController.cs
index d54981ff45..98e80aba25 100644
--- a/src/Umbraco.Web/Editors/MediaTypeController.cs
+++ b/src/Umbraco.Web/Editors/MediaTypeController.cs
@@ -134,9 +134,10 @@ namespace Umbraco.Web.Editors
public ContentTypeCompositionDisplay PostSave(ContentTypeSave contentTypeSave)
{
var savedCt = PerformPostSave(
- contentTypeSave: contentTypeSave,
- getContentType: i => Services.ContentTypeService.GetMediaType(i),
- saveContentType: type => Services.ContentTypeService.Save(type));
+ contentTypeSave: contentTypeSave,
+ getContentType: i => Services.ContentTypeService.GetMediaType(i),
+ getContentTypeByAlias: alias => Services.ContentTypeService.GetMediaType(alias),
+ saveContentType: type => Services.ContentTypeService.Save(type));
var display = Mapper.Map(savedCt);
diff --git a/src/Umbraco.Web/Editors/MemberTypeController.cs b/src/Umbraco.Web/Editors/MemberTypeController.cs
index 7716f6ea00..44eafe1500 100644
--- a/src/Umbraco.Web/Editors/MemberTypeController.cs
+++ b/src/Umbraco.Web/Editors/MemberTypeController.cs
@@ -110,10 +110,11 @@ namespace Umbraco.Web.Editors
public ContentTypeCompositionDisplay PostSave(ContentTypeSave contentTypeSave)
{
var savedCt = PerformPostSave(
- contentTypeSave: contentTypeSave,
- getContentType: i => Services.MemberTypeService.Get(i),
- saveContentType: type => Services.MemberTypeService.Save(type),
- validateComposition: false);
+ contentTypeSave: contentTypeSave,
+ getContentType: i => Services.MemberTypeService.Get(i),
+ getContentTypeByAlias: alias => Services.MemberTypeService.Get(alias),
+ saveContentType: type => Services.MemberTypeService.Save(type),
+ validateComposition: false);
var display = Mapper.Map(savedCt);