Fixes some property editors ensuring ngModelController(#10013)

Co-authored-by: Niels Lyngsø <nsl@umbraco.com>
This commit is contained in:
Shannon Deminick
2021-04-12 23:19:32 +10:00
committed by GitHub
parent 18fa631f1c
commit de4a7eff85
32 changed files with 460 additions and 334 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -129,6 +129,8 @@
replace: true,
templateUrl: 'views/components/buttons/umb-toggle.html',
scope: {
// TODO: This should have required ngModel so we can track and validate user input correctly
// https://docs.angularjs.org/api/ng/type/ngModel.NgModelController#custom-control-example
checked: "=",
disabled: "=",
inputId: "@",

View File

@@ -35,6 +35,12 @@
vm.$onInit = onInit;
vm.setDirty = function () {
// NOTE: We need to use scope because we haven't changd it to vm.propertyForm in the html and that
// might mean a breaking change.
$scope.propertyForm.$setDirty();
}
vm.setPropertyError = function (errorMsg) {
vm.property.propertyErrorMessage = errorMsg;
};

View File

@@ -44,9 +44,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
this.isShowingValidation = () => $scope.showValidation === true;
this.notify = function () {
notify($scope);
}
this.notify = notify;
this.isValid = function () {
return !$scope.formCtrl.$invalid;
@@ -112,6 +110,7 @@ function valFormManager(serverValidationManager, $rootScope, $timeout, $location
});
//watch the list of validation errors to notify the application of any validation changes
// TODO: Wouldn't it be easier/faster to watch formCtrl.$invalid ?
scope.$watch(() => angularHelper.countAllFormErrors(formCtrl),
function (e) {

View File

@@ -177,8 +177,9 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
watcher = scope.$watchCollection(
() => formCtrl,
function (updatedFormController) {
var ngModels = [];
collectAllNgModelControllersRecursively(updatedFormController.$getControls(), ngModels);
let childControls = updatedFormController.$getControls();
let ngModels = [];
collectAllNgModelControllersRecursively(childControls, ngModels);
ngModels.forEach(x => {
if (!x.$validators.serverValidityResetter) {
x.$validators.serverValidityResetter = resetServerValidityValidator(x);
@@ -201,7 +202,7 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
hasError = false;
formCtrl.$setValidity('valPropertyMsg', true);
scope.errorMsg = "";
}
// This deals with client side validation changes and is executed anytime validators change on the containing
@@ -264,6 +265,8 @@ function valPropertyMsg(serverValidationManager, localizationService, angularHel
//listen for form validation changes.
//The alternative is to add a watch to formCtrl.$invalid but that would lead to many more watches then
// subscribing to this single watch.
// TODO: Really? Since valFormManager is watching a countof all errors which is more overhead than watching formCtrl.$invalid
// and there's a TODO there that it should just watch formCtrl.$invalid
valFormManager.onValidationStatusChanged(function (evt, args) {
checkValidationStatus();
});

View File

@@ -1,4 +1,4 @@
function booleanEditorController($scope, angularHelper) {
function booleanEditorController($scope) {
// Setup the default config
// This allow to overwrite the configuration when property editor is re-used
@@ -36,6 +36,12 @@ function booleanEditorController($scope, angularHelper) {
}
}
function setDirty() {
if ($scope.modelValueForm) {
$scope.modelValueForm.modelValue.$setDirty();
}
}
setupViewModel();
if ($scope.model && !$scope.model.value) {
@@ -51,7 +57,7 @@ function booleanEditorController($scope, angularHelper) {
// Update the value when the toggle is clicked
$scope.toggle = function(){
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
if ($scope.renderModel.value){
$scope.model.value = $scope.model.config.falsevalue;
setupViewModel();

View File

@@ -1,11 +1,17 @@
<div class="umb-property-editor umb-boolean" ng-controller="Umbraco.PropertyEditors.BooleanController">
<umb-toggle
input-id="{{model.alias}}"
checked="renderModel.value"
on-click="toggle()"
show-labels="{{model.config.showLabels}}"
label-position="right"
label-on="{{model.config.labelOn}}"
label-off="{{model.config.labelOff}}">
</umb-toggle>
<ng-form name="modelValueForm">
<umb-toggle input-id="{{model.alias}}"
checked="renderModel.value"
on-click="toggle()"
show-labels="{{model.config.showLabels}}"
label-position="right"
label-on="{{model.config.labelOn}}"
label-off="{{model.config.labelOff}}">
</umb-toggle>
<input type="hidden" name="modelValue" ng-model="renderModel.value" />
</ng-form>
</div>

View File

@@ -63,7 +63,7 @@ function ColorPickerController($scope, $timeout) {
// this is required to re-validate
$timeout(function () {
var newColor = color ? color.value : null;
$scope.propertyForm.selectedColor.$setViewValue(newColor);
vm.modelValueForm.selectedColor.$setViewValue(newColor);
});
};

View File

@@ -1,17 +1,19 @@
<div ng-controller="Umbraco.PropertyEditors.ColorPickerController as vm">
<div ng-if="!isConfigured">
<localize key="colorpicker_noColors">You haven't defined any colors</localize>
</div>
<ng-form name="vm.modelValueForm">
<div ng-if="!isConfigured">
<localize key="colorpicker_noColors">You haven't defined any colors</localize>
</div>
<umb-color-swatches
colors="model.config.items"
selected-color="model.value"
size="m"
use-label="model.useLabel"
on-select="vm.selectColor(color)">
</umb-color-swatches>
<umb-color-swatches colors="model.config.items"
selected-color="model.value"
size="m"
use-label="model.useLabel"
on-select="vm.selectColor(color)">
</umb-color-swatches>
<input type="hidden" name="selectedColor" ng-model="model.selectedColor" val-property-validator="validateMandatory" />
<input type="hidden" name="selectedColor" ng-model="model.selectedColor" val-property-validator="validateMandatory" />
</ng-form>
</div>

View File

@@ -104,7 +104,7 @@
return x.value === item.value && x.label === item.label;
});
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
}
function add(evt) {
@@ -130,7 +130,7 @@
$scope.newLabel = "";
$scope.hasError = false;
$scope.focusOnNew = true;
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
return;
}
@@ -156,6 +156,12 @@
$scope.newLabel = defaultLabel;
}
function setDirty() {
if (vm.modelValueForm) {
vm.modelValueForm.selectedColor.$setDirty();
}
}
$scope.sortableOptions = {
axis: 'y',
containment: 'parent',
@@ -164,7 +170,7 @@
items: '> div.control-group',
tolerance: 'pointer',
update: function (e, ui) {
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
}
};

View File

@@ -15,7 +15,7 @@
* @param {any} editorService
* @param {any} userService
*/
function contentPickerController($scope, $q, $routeParams, $location, entityResource, editorState, iconHelper, angularHelper, navigationService, localizationService, editorService, userService, overlayService) {
function contentPickerController($scope, $q, $routeParams, $location, entityResource, editorState, iconHelper, navigationService, localizationService, editorService, userService, overlayService) {
var vm = {
labels: {
@@ -112,7 +112,7 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
scroll: true,
zIndex: 6000,
update: function (e, ui) {
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
}
};
@@ -180,7 +180,7 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
$scope.clear();
$scope.add(data);
}
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
},
treeAlias: $scope.model.config.startNode.type,
section: $scope.model.config.startNode.type,
@@ -257,9 +257,9 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
_.each(model.selection, function (item, i) {
$scope.add(item);
});
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
}
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
editorService.close();
}
@@ -288,7 +288,7 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
var currIds = $scope.model.value ? $scope.model.value.split(',') : [];
if (currIds.length > 0) {
currIds.splice(index, 1);
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
$scope.model.value = currIds.join();
}
@@ -375,6 +375,12 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
}
});
function setDirty() {
if ($scope.contentPickerForm && $scope.contentPickerForm.modelValue) {
$scope.contentPickerForm.modelValue.$setDirty();
}
}
/** Syncs the renderModel based on the actual model.value and returns a promise */
function syncRenderModel(doValidation) {

View File

@@ -19,14 +19,12 @@
</umb-node-preview>
</div>
<button
ng-show="model.config.multiPicker === true && renderModel.length < model.config.maxNumber || renderModel.length === 0 || !model.config.maxNumber"
type="button"
class="umb-node-preview-add"
ng-click="openCurrentPicker()"
id="{{model.alias}}"
aria-label="{{model.label}}: {{labels.general_add}}"
>
<button ng-show="model.config.multiPicker === true && renderModel.length < model.config.maxNumber || renderModel.length === 0 || !model.config.maxNumber"
type="button"
class="umb-node-preview-add"
ng-click="openCurrentPicker()"
id="{{model.alias}}"
aria-label="{{model.label}}: {{labels.general_add}}">
<localize key="general_add">Add</localize>
<span class="sr-only">...</span>
</button>
@@ -64,16 +62,18 @@
</div>
<input type="hidden" name="modelValue" ng-model="model.value" />
<!--These are here because we need ng-form fields to validate against-->
<input type="hidden" name="minCount" ng-model="renderModel" />
<input type="hidden" name="maxCount" ng-model="renderModel" />
<div ng-messages="contentPickerForm.minCount.$error" show-validation-on-submit >
<div ng-messages="contentPickerForm.minCount.$error" show-validation-on-submit>
<div class="help-inline" ng-message="minCount">
<localize key="validation_minCount">You need to add at least</localize> {{model.config.minNumber}} <localize key="validation_items">items</localize>
</div>
</div>
<div ng-messages="contentPickerForm.maxCount.$error" show-validation-on-submit >
<div ng-messages="contentPickerForm.maxCount.$error" show-validation-on-submit>
<div class="help-inline" ng-message="maxCount">
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected">items selected</localize>
</div>

View File

@@ -161,7 +161,14 @@ function dateTimePickerController($scope, angularHelper, dateHelper, validationM
else {
$scope.model.value = null;
}
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
}
function setDirty() {
if ($scope.datePickerForm) {
$scope.datePickerForm.datepicker.$setDirty();
}
}
/** Sets the value of the date picker control adn associated viewModel objects based on the model value */

View File

@@ -31,7 +31,7 @@ angular.module('umbraco')
};
//set form to dirty to track changes
$scope.imageCropperForm.$setDirty();
setDirty();
}
/**
@@ -67,7 +67,13 @@ angular.module('umbraco')
function onFileSelected(value, files) {
setModelValueWithSrc(value);
//set form to dirty to track changes
$scope.imageCropperForm.$setDirty();
setDirty();
}
function setDirty() {
if ($scope.imageCropperForm) {
$scope.imageCropperForm.modelValue.$setDirty();
}
}
function imageLoaded(isCroppable, hasDimensions) {
@@ -84,7 +90,7 @@ angular.module('umbraco')
if (files && files[0]) {
$scope.imageSrc = files[0].fileSrc;
//set form to dirty to track changes
$scope.imageCropperForm.$setDirty();
setDirty();
}
}
@@ -138,7 +144,7 @@ angular.module('umbraco')
$scope.currentPoint = null;
//set form to dirty to track changes
$scope.imageCropperForm.$setDirty();
setDirty();
}
else {
// we have a crop open already - close the crop (this will discard any changes made)
@@ -168,7 +174,7 @@ angular.module('umbraco')
$scope.close();
//set form to dirty to track changes
$scope.imageCropperForm.$setDirty();
setDirty();
};
function reset() {
@@ -201,7 +207,7 @@ angular.module('umbraco')
}
//set form to dirty to track changes
$scope.imageCropperForm.$setDirty();
setDirty();
};
function isCustomCrop(crop) {

View File

@@ -2,6 +2,9 @@
ng-controller="Umbraco.PropertyEditors.ImageCropperController">
<ng-form name="imageCropperForm">
<input type="hidden" name="modelValue" ng-model="model.value" />
<umb-property-file-upload culture="{{model.culture}}"
segment="{{model.segment}}"
property-alias="{{model.alias}}"

View File

@@ -1,5 +1,5 @@
//inject umbracos assetsServce and dialog service
function MarkdownEditorController($scope, $element, assetsService, editorService, angularHelper, $timeout) {
function MarkdownEditorController($scope, $element, assetsService, editorService, $timeout) {
//tell the assets service to load the markdown.editor libs from the markdown editors
//plugin folder
@@ -41,6 +41,12 @@ function MarkdownEditorController($scope, $element, assetsService, editorService
editorService.linkPicker(linkPicker);
}
function setDirty() {
if ($scope.modelValueForm) {
$scope.modelValueForm.modelValue.$setDirty();
}
}
assetsService
.load([
"lib/markdown/markdown.converter.js",
@@ -78,7 +84,7 @@ function MarkdownEditorController($scope, $element, assetsService, editorService
if ($scope.model.value !== $("textarea", $element).val()) {
if ($scope.markdownEditorInitComplete) {
//only set dirty after init load to avoid "unsaved" dialogue when we don't want it
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
} else {
$scope.markdownEditorInitComplete = true;
}

View File

@@ -1,8 +1,11 @@
<div class="wmd-panel" ng-controller="Umbraco.PropertyEditors.MarkdownEditorController">
<div id="wmd-button-bar-{{editorId}}"></div>
<textarea class="wmd-input" id="wmd-input-{{editorId}}" ng-model="model.value" ng-required="model.validation.mandatory"></textarea>
<ng-form name="modelValueForm">
<div id="wmd-button-bar-{{editorId}}"></div>
<div class="wmd-panel wmd-preview" id="wmd-preview-{{editorId}}" ng-show="model.config.preview"></div>
<textarea name="modelValue" class="wmd-input" id="wmd-input-{{editorId}}" ng-model="model.value" ng-required="model.validation.mandatory"></textarea>
<div class="wmd-panel wmd-preview" id="wmd-preview-{{editorId}}" ng-show="model.config.preview"></div>
</ng-form>
</div>

View File

@@ -1,7 +1,7 @@
//this controller simply tells the dialogs service to open a mediaPicker window
//with a specified callback, this callback will receive an object with a selection on it
angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerController",
function ($scope, entityResource, mediaHelper, $timeout, userService, localizationService, editorService, angularHelper, overlayService) {
function ($scope, entityResource, mediaHelper, $timeout, userService, localizationService, editorService, overlayService) {
var vm = this;
@@ -13,6 +13,9 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
vm.editItem = editItem;
vm.showAdd = showAdd;
vm.mediaItems = [];
let selectedIds = [];
//check the pre-values for multi-picker
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
var onlyImages = $scope.model.config.onlyImages && $scope.model.config.onlyImages !== '0' ? true : false;
@@ -22,9 +25,6 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
$scope.allowAddMedia = false;
function setupViewModel() {
$scope.mediaItems = [];
$scope.ids = [];
$scope.isMultiPicker = multiPicker;
if ($scope.model.value) {
@@ -77,12 +77,12 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
}
$scope.mediaItems.push(media);
vm.mediaItems.push(media);
if ($scope.model.config.idType === "udi") {
$scope.ids.push(media.udi);
selectedIds.push(media.udi);
} else {
$scope.ids.push(media.id);
selectedIds.push(media.id);
}
});
@@ -92,12 +92,14 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
}
function sync() {
$scope.model.value = $scope.ids.join();
removeAllEntriesAction.isDisabled = $scope.ids.length === 0;
$scope.model.value = selectedIds.join();
removeAllEntriesAction.isDisabled = selectedIds.length === 0;
}
function setDirty() {
angularHelper.getCurrentForm($scope).$setDirty();
if (vm.modelValueForm) {
vm.modelValueForm.modelValue.$setDirty();
}
}
function reloadUpdatedMediaItems(updatedMediaNodes) {
@@ -105,7 +107,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
// reload. We only reload the images that is already picked but has been updated.
// We have to get the entities from the server because the media
// can be edited without being selected
$scope.mediaItems.forEach(media => {
vm.mediaItems.forEach(media => {
if (updatedMediaNodes.indexOf(media.udi) !== -1) {
media.loading = true;
entityResource.getById(media.udi, "Media")
@@ -155,8 +157,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
}
function remove(index) {
$scope.mediaItems.splice(index, 1);
$scope.ids.splice(index, 1);
vm.mediaItems.splice(index, 1);
selectedIds.splice(index, 1);
sync();
setDirty();
}
@@ -174,7 +176,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
.then(function (mediaEntity) {
// if an image is selecting more than once
// we need to update all the media items
$scope.mediaItems.forEach(media => {
vm.mediaItems.forEach(media => {
if (media.id === model.mediaNode.id) {
angular.extend(media, mediaEntity);
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
@@ -208,13 +210,13 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
media.thumbnail = mediaHelper.resolveFileFromEntity(media, true);
}
$scope.mediaItems.push(media);
vm.mediaItems.push(media);
if ($scope.model.config.idType === "udi") {
$scope.ids.push(media.udi);
selectedIds.push(media.udi);
}
else {
$scope.ids.push(media.id);
selectedIds.push(media.id);
}
});
@@ -250,8 +252,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
overlayService.close();
},
submit: function () {
$scope.mediaItems.length = 0;// AngularJS way to empty the array.
$scope.ids.length = 0;// AngularJS way to empty the array.
vm.mediaItems.length = 0;// AngularJS way to empty the array.
selectedIds.length = 0;// AngularJS way to empty the array.
sync();
setDirty();
overlayService.close();
@@ -291,7 +293,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
// TODO: Instead of doing this with a timeout would be better to use a watch like we do in the
// content picker. Then we don't have to worry about setting ids, render models, models, we just set one and let the
// watch do all the rest.
$scope.ids = $scope.mediaItems.map(media => $scope.model.config.idType === "udi" ? media.udi : media.id);
selectedIds = vm.mediaItems.map(media => $scope.model.config.idType === "udi" ? media.udi : media.id);
sync();
});

View File

@@ -1,11 +1,11 @@
<div class="umb-property-editor umb-mediapicker" ng-class="{'umb-mediapicker-multi':isMultiPicker, 'umb-mediapicker-single':!isMultiPicker}" ng-controller="Umbraco.PropertyEditors.MediaPickerController as vm">
<p ng-if="(mediaItems|filter:{trashed:true}).length == 1"><localize key="mediaPicker_pickedTrashedItem"></localize></p>
<p ng-if="(mediaItems|filter:{trashed:true}).length > 1"><localize key="mediaPicker_pickedTrashedItems"></localize></p>
<p ng-if="(vm.mediaItems|filter:{trashed:true}).length == 1"><localize key="mediaPicker_pickedTrashedItem"></localize></p>
<p ng-if="(vm.mediaItems|filter:{trashed:true}).length > 1"><localize key="mediaPicker_pickedTrashedItems"></localize></p>
<div data-element="sortable-thumbnails" class="umb-sortable-thumbnails-container error">
<ul ui-sortable="sortableOptions" ng-model="mediaItems" class="umb-sortable-thumbnails">
<li data-element="sortable-thumbnail-{{$index}}" class="umb-sortable-thumbnails__wrapper" ng-repeat="media in mediaItems track by $index">
<ul ui-sortable="sortableOptions" ng-model="vm.mediaItems" class="umb-sortable-thumbnails">
<li data-element="sortable-thumbnail-{{$index}}" class="umb-sortable-thumbnails__wrapper" ng-repeat="media in vm.mediaItems track by $index">
<p class="label label__trashed" ng-if="media.trashed">
<localize key="mediaPicker_trashed"></localize>
@@ -46,13 +46,15 @@
</div>
</li>
<li style="border: none;" class="add-wrapper unsortable" ng-if="vm.showAdd() && allowAddMedia">
<button type="button" aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link btn-reset umb-outline umb-outline--surrounding" ng-click="vm.add()" ng-class="{'add-link-square': (mediaItems.length === 0 || isMultiPicker)}">
<button type="button" aria-label="Open media picker" data-element="sortable-thumbnails-add" class="add-link btn-reset umb-outline umb-outline--surrounding" ng-click="vm.add()" ng-class="{'add-link-square': (vm.mediaItems.length === 0 || isMultiPicker)}">
<i class="icon icon-add large" aria-hidden="true"></i>
</button>
</li>
</ul>
</div>
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !mediaItems.length" />
<ng-form name="vm.modelValueForm">
<input type="hidden" name="modelValue" ng-model="vm.mediaItems.length" ng-required="model.validation.mandatory && !vm.mediaItems.length" />
</ng-form>
</div>

View File

@@ -18,6 +18,12 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
});
}
function setDirty() {
if ($scope.modelValueForm) {
$scope.modelValueForm.modelValue.$setDirty();
}
}
$scope.openMemberGroupPicker = function() {
var memberGroupPicker = {
multiPicker: true,
@@ -32,6 +38,7 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
if (newGroupIds && newGroupIds.length) {
memberGroupResource.getByIds(newGroupIds).then(function (groups) {
$scope.renderModel = _.union($scope.renderModel, groups);
setDirty();
editorService.close();
});
}
@@ -47,10 +54,13 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
editorService.memberGroupPicker(memberGroupPicker);
};
$scope.remove =function(index){
// TODO: I don't believe this is used
$scope.remove = function(index){
$scope.renderModel.splice(index, 1);
setDirty();
};
// TODO: I don't believe this is used
$scope.add = function (item) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
@@ -58,11 +68,14 @@ function memberGroupPicker($scope, editorService, memberGroupResource){
if (currIds.indexOf(item) < 0) {
$scope.renderModel.push({ name: item, id: item, icon: 'icon-users' });
setDirty();
}
};
// TODO: I don't believe this is used
$scope.clear = function() {
$scope.renderModel = [];
setDirty();
};
function renderModelIds() {

View File

@@ -1,21 +1,22 @@
<div ng-controller="Umbraco.PropertyEditors.MemberGroupPickerController" class="umb-property-editor umb-membergrouppicker">
<div ng-model="renderModel">
<umb-node-preview
ng-repeat="node in renderModel | orderBy:'name'"
icon="node.icon"
name="node.name"
allow-remove="allowRemove"
on-remove="remove($index)">
<umb-node-preview ng-repeat="node in renderModel | orderBy:'name'"
icon="node.icon"
name="node.name"
allow-remove="allowRemove"
on-remove="remove($index)">
</umb-node-preview>
</div>
<button type="button"
class="umb-node-preview-add"
ng-click="openMemberGroupPicker()">
class="umb-node-preview-add"
ng-click="openMemberGroupPicker()">
<localize key="general_add">Add</localize>
</button>
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
<ng-form name="modelValueForm">
<input type="hidden" name="modelValue" ng-model="renderModel.length" ng-required="model.validation.mandatory && !renderModel.length" />
</ng-form>
</div>

View File

@@ -10,6 +10,12 @@
return selected;
};
function setDirty() {
if ($scope.modelValueForm) {
$scope.modelValueForm.modelValue.$setDirty();
}
}
$scope.pickGroup = function() {
editorService.memberGroupPicker({
multiPicker: true,
@@ -24,6 +30,7 @@
$scope.model.value[group.name] = true;
});
});
setDirty();
editorService.close();
},
close: function () {
@@ -34,6 +41,7 @@
$scope.removeGroup = function (group) {
$scope.model.value[group] = false;
setDirty();
}
}
angular.module('umbraco').controller("Umbraco.PropertyEditors.MemberGroupController", memberGroupController);

View File

@@ -12,4 +12,9 @@
ng-click="pickGroup()">
<localize key="general_add">Add</localize>
</button>
<ng-form name="modelValueForm">
<input type="hidden" name="modelValue" ng-model="model.value" />
</ng-form>
</div>

View File

@@ -1,6 +1,6 @@
//this controller simply tells the dialogs service to open a memberPicker window
//with a specified callback, this callback will receive an object with a selection on it
function memberPickerController($scope, entityResource, iconHelper, angularHelper, editorService){
function memberPickerController($scope, entityResource, iconHelper, editorService){
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
@@ -27,11 +27,16 @@ function memberPickerController($scope, entityResource, iconHelper, angularHelpe
} else {
$scope.clear();
$scope.add(data);
}
angularHelper.getCurrentForm($scope).$setDirty();
}
}
};
function setDirty() {
if ($scope.modelValueForm) {
$scope.modelValueForm.modelValue.$setDirty();
}
}
//since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the
// pre-value config on to the dialog options
if ($scope.model.config) {
@@ -60,6 +65,7 @@ function memberPickerController($scope, entityResource, iconHelper, angularHelpe
$scope.remove = function (index) {
$scope.renderModel.splice(index, 1);
setDirty();
};
$scope.add = function (item) {
@@ -76,7 +82,8 @@ function memberPickerController($scope, entityResource, iconHelper, angularHelpe
if (currIds.indexOf(itemId) < 0) {
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon});
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon });
setDirty();
}
};

View File

@@ -1,22 +1,23 @@
<div ng-controller="Umbraco.PropertyEditors.MemberPickerController" class="umb-property-editor umb-memberpicker">
<div>
<umb-node-preview
ng-repeat="node in renderModel"
icon="node.icon"
name="node.name"
allow-remove="allowRemove"
on-remove="remove($index)">
<umb-node-preview ng-repeat="node in renderModel"
icon="node.icon"
name="node.name"
allow-remove="allowRemove"
on-remove="remove($index)">
</umb-node-preview>
</div>
<button type="button"
class="umb-node-preview-add"
ng-show="model.config.multiPicker === true || renderModel.length === 0"
ng-click="openMemberPicker()">
class="umb-node-preview-add"
ng-show="model.config.multiPicker === true || renderModel.length === 0"
ng-click="openMemberPicker()">
<localize key="general_add">Add</localize>
</button>
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
<ng-form name="modelValueForm">
<input type="hidden" name="modelValue" ng-model="renderModel.length" ng-required="model.validation.mandatory && !renderModel.length" />
</ng-form>
</div>

View File

@@ -1,4 +1,4 @@
function multiUrlPickerController($scope, angularHelper, localizationService, entityResource, iconHelper, editorService) {
function multiUrlPickerController($scope, localizationService, entityResource, iconHelper, editorService) {
var vm = {
labels: {
@@ -16,8 +16,6 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
$scope.model.value = [];
}
var currentForm = angularHelper.getCurrentForm($scope);
$scope.sortableOptions = {
axis: "y",
containment: "parent",
@@ -27,7 +25,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
scroll: true,
zIndex: 6000,
update: function () {
currentForm.$setDirty();
setDirty();
}
};
@@ -66,7 +64,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
$scope.remove = function ($index) {
$scope.renderModel.splice($index, 1);
currentForm.$setDirty();
setDirty();
};
$scope.openLinkPicker = function (link, $index) {
@@ -122,7 +120,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
link.published = true;
}
currentForm.$setDirty();
setDirty();
}
editorService.close();
},
@@ -133,6 +131,12 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
editorService.linkPicker(linkPicker);
};
function setDirty() {
if ($scope.multiUrlPickerForm) {
$scope.multiUrlPickerForm.modelValue.$setDirty();
}
}
function init() {
localizationService.localizeMany(["general_recycleBin"])
.then(function (data) {

View File

@@ -18,9 +18,9 @@
</div>
<button ng-show="!model.config.maxNumber || renderModel.length < model.config.maxNumber"
type="button"
class="umb-node-preview-add"
ng-click="openLinkPicker()">
type="button"
class="umb-node-preview-add"
ng-click="openLinkPicker()">
<span class="sr-only">{{ model.label }}:</span>
<localize key="general_add">Add</localize>
<span class="sr-only">url</span>
@@ -60,6 +60,8 @@
</div>
<input type="hidden" name="modelValue" ng-model="renderModel.length" />
<!--These are here because we need ng-form fields to validate against-->
<input type="hidden" name="minCount" ng-model="renderModel" />
<input type="hidden" name="maxCount" ng-model="renderModel" />

View File

@@ -169,11 +169,14 @@
method: removeAllEntries,
isDisabled: true
};
// helper to force the current form into the dirty state
function setDirty() {
if ($scope.$parent.$parent.propertyForm) {
$scope.$parent.$parent.propertyForm.$setDirty();
if (vm.umbProperty) {
vm.umbProperty.setDirty();
}
};
function addNode(alias) {

View File

@@ -1,4 +1,4 @@
function sliderController($scope, angularHelper) {
function sliderController($scope) {
let sliderRef = null;
@@ -14,7 +14,13 @@
function setModelValue(values) {
$scope.model.value = values ? values.toString() : null;
angularHelper.getCurrentForm($scope).$setDirty();
setDirty();
}
function setDirty() {
if ($scope.modelValueForm) {
$scope.modelValueForm.modelValue.$setDirty();
}
}
$scope.setup = function(slider) {

View File

@@ -1,12 +1,14 @@
<div class="umb-property-editor umb-slider" ng-controller="Umbraco.PropertyEditors.SliderController">
<div style="padding-top: 50px; padding-bottom: 40px;">
<umb-range-slider
ng-model="sliderValue"
options="sliderOptions"
on-setup="setup(slider)"
on-change="change(values)">
</umb-range-slider>
</div>
<ng-form name="modelValueForm">
<div style="padding-top: 50px; padding-bottom: 40px;">
<umb-range-slider ng-model="sliderValue"
options="sliderOptions"
on-setup="setup(slider)"
on-change="change(values)">
</umb-range-slider>
</div>
<input type="hidden" name="modelValue" ng-model="model.value" />
</ng-form>
</div>

View File

@@ -10,6 +10,12 @@ function userPickerController($scope, iconHelper, editorService, overlayService,
var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false;
function setDirty() {
if ($scope.modelValueForm) {
$scope.modelValueForm.modelValue.$setDirty();
}
}
$scope.openUserPicker = function () {
var currentSelection = [];
@@ -42,7 +48,7 @@ function userPickerController($scope, iconHelper, editorService, overlayService,
submit: function () {
$scope.renderModel.splice(index, 1);
$scope.userName = '';
setDirty();
overlayService.close();
},
close: function () {
@@ -68,11 +74,13 @@ function userPickerController($scope, iconHelper, editorService, overlayService,
if (currIds.indexOf(itemId) < 0) {
item.icon = item.icon ? iconHelper.convertFromLegacyIcon(item.icon) : "icon-user";
$scope.renderModel.push({ name: item.name, id: item.id, udi: item.udi, icon: item.icon, avatars: item.avatars });
setDirty();
}
};
$scope.clear = function() {
$scope.renderModel = [];
setDirty();
};
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {

View File

@@ -1,21 +1,22 @@
<div ng-controller="Umbraco.PropertyEditors.UserPickerController" class="umb-property-editor umb-userpicker">
<div>
<umb-user-preview
ng-repeat="user in renderModel"
name="user.name"
avatars="user.avatars"
allow-remove="allowRemove"
on-remove="remove($index)">
<div>
<umb-user-preview ng-repeat="user in renderModel"
name="user.name"
avatars="user.avatars"
allow-remove="allowRemove"
on-remove="remove($index)">
</umb-user-preview>
</div>
</div>
<button type="button" ng-show="model.config.multiPicker === true || renderModel.length === 0"
class="umb-node-preview-add"
ng-click="openUserPicker()">
<localize key="general_add">Add</localize>
</button>
<button type="button" ng-show="model.config.multiPicker === true || renderModel.length === 0"
class="umb-node-preview-add"
ng-click="openUserPicker()">
<localize key="general_add">Add</localize>
</button>
<input type="hidden" name="mandatory" ng-model="model.mandatory" ng-required="model.validation.mandatory && !renderModel.length" />
<ng-form name="modelValueForm">
<input type="hidden" name="modelValue" ng-model="renderModel.length" ng-required="model.validation.mandatory && !renderModel.length" />
</ng-form>
</div>