Skip to content

Commit 8733230

Browse files
Property Editors: Added form control and mandatory support to editors in common group(Number, Tags, Slider). (#20659)
* Added mandatory support to property-editor-ui-number. * Added form control to property-editor-ui-tags * Added validator to the slider when value is missing and support for mandatory and mandatory message. * Removed unnecessary ternary. * Removed white space lit error. * Fix tags input to handle undefined items array --------- Co-authored-by: Mads Rasmussen <[email protected]>
1 parent 498bb5e commit 8733230

File tree

6 files changed

+98
-14
lines changed

6 files changed

+98
-14
lines changed

src/Umbraco.Web.UI.Client/src/packages/core/components/input-slider/input-slider.element.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,23 @@ import { customElement, html, property } from '@umbraco-cms/backoffice/external/
33
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
44
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
55
import type { UUISliderEvent } from '@umbraco-cms/backoffice/external/uui';
6+
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY } from '@umbraco-cms/backoffice/validation';
67

8+
/**
9+
*
10+
* @param value
11+
*/
712
function splitString(value: string | undefined): Partial<[number | undefined, number | undefined]> {
813
const [from, to] = (value ?? ',').split(',');
914
const fromNumber = makeNumberOrUndefined(from);
1015
return [fromNumber, makeNumberOrUndefined(to, fromNumber)];
1116
}
1217

18+
/**
19+
*
20+
* @param value
21+
* @param fallback
22+
*/
1323
function makeNumberOrUndefined(value: string | undefined, fallback?: undefined | number) {
1424
if (value === undefined) {
1525
return fallback;
@@ -21,6 +31,11 @@ function makeNumberOrUndefined(value: string | undefined, fallback?: undefined |
2131
return n;
2232
}
2333

34+
/**
35+
*
36+
* @param value
37+
* @param fallback
38+
*/
2439
function undefinedFallbackToString(value: number | undefined, fallback: number): string {
2540
return (value === undefined ? fallback : value).toString();
2641
}
@@ -48,6 +63,15 @@ export class UmbInputSliderElement extends UmbFormControlMixin<string, typeof Um
4863

4964
@property({ type: Number })
5065
step = 1;
66+
/**
67+
* Sets the input to required, meaning validation will fail if the value is empty.
68+
* @type {boolean}
69+
*/
70+
@property({ type: Boolean })
71+
required?: boolean;
72+
73+
@property({ type: String })
74+
requiredMessage?: string;
5175

5276
@property({ type: Number })
5377
public get valueLow(): number | undefined {
@@ -92,6 +116,12 @@ export class UmbInputSliderElement extends UmbFormControlMixin<string, typeof Um
92116
constructor() {
93117
super();
94118

119+
this.addValidator(
120+
'valueMissing',
121+
() => this.requiredMessage ?? UMB_VALIDATION_EMPTY_LOCALIZATION_KEY,
122+
() => !this.readonly && !!this.required && (this.value === undefined || this.value === null || this.value === ''),
123+
);
124+
95125
this.addValidator(
96126
'rangeUnderflow',
97127
() => {

src/Umbraco.Web.UI.Client/src/packages/property-editors/number/property-editor-ui-number.element.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { css, customElement, html, ifDefined, property, state } from '@umbraco-cms/backoffice/external/lit';
2-
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
2+
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
33
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
44
import { UMB_PROPERTY_CONTEXT } from '@umbraco-cms/backoffice/property';
55
import type {
@@ -10,7 +10,7 @@ import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
1010

1111
@customElement('umb-property-editor-ui-number')
1212
export class UmbPropertyEditorUINumberElement
13-
extends UmbFormControlMixin<number | undefined, typeof UmbLitElement, undefined>(UmbLitElement)
13+
extends UmbFormControlMixin<number, typeof UmbLitElement, undefined>(UmbLitElement, undefined)
1414
implements UmbPropertyEditorUiElement
1515
{
1616
/**
@@ -22,6 +22,15 @@ export class UmbPropertyEditorUINumberElement
2222
@property({ type: Boolean, reflect: true })
2323
readonly = false;
2424

25+
/**
26+
* Sets the input to mandatory, meaning validation will fail if the value is empty.
27+
* @type {boolean}
28+
*/
29+
@property({ type: Boolean })
30+
mandatory?: boolean;
31+
@property({ type: String })
32+
mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY;
33+
2534
@state()
2635
private _label?: string;
2736

@@ -78,6 +87,7 @@ export class UmbPropertyEditorUINumberElement
7887
this,
7988
);
8089
}
90+
this.addFormControlElement(this.shadowRoot!.querySelector('uui-input')!);
8191
}
8292

8393
#parseNumber(input: unknown): number | undefined {
@@ -103,6 +113,8 @@ export class UmbPropertyEditorUINumberElement
103113
placeholder=${ifDefined(this._placeholder)}
104114
value=${this.value?.toString() ?? ''}
105115
@change=${this.#onChange}
116+
?required=${this.mandatory}
117+
.requiredMessage=${this.mandatoryMessage}
106118
?readonly=${this.readonly}>
107119
</uui-input>
108120
`;

src/Umbraco.Web.UI.Client/src/packages/property-editors/slider/property-editor-ui-slider.element.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,23 @@ import type {
88
UmbPropertyEditorConfigCollection,
99
UmbPropertyEditorUiElement,
1010
} from '@umbraco-cms/backoffice/property-editor';
11-
import { UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
11+
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
1212

13+
/**
14+
*
15+
* @param value
16+
*/
1317
function stringToValueObject(value: string | undefined): Partial<UmbSliderPropertyEditorUiValueObject> {
1418
const [from, to] = (value ?? ',').split(',');
1519
const fromNumber = makeNumberOrUndefined(from);
1620
return { from: fromNumber, to: makeNumberOrUndefined(to, fromNumber) };
1721
}
1822

23+
/**
24+
*
25+
* @param value
26+
* @param fallback
27+
*/
1928
function makeNumberOrUndefined(value: string | undefined, fallback?: undefined | number) {
2029
if (value === undefined) {
2130
return fallback;
@@ -27,6 +36,11 @@ function makeNumberOrUndefined(value: string | undefined, fallback?: undefined |
2736
return n;
2837
}
2938

39+
/**
40+
*
41+
* @param value
42+
* @param fallback
43+
*/
3044
function undefinedFallback(value: number | undefined, fallback: number) {
3145
return value === undefined ? fallback : value;
3246
}
@@ -48,6 +62,16 @@ export class UmbPropertyEditorUISliderElement
4862
@property({ type: Boolean, reflect: true })
4963
readonly = false;
5064

65+
/**
66+
* Sets the input to mandatory, meaning validation will fail if the value is empty.
67+
* @type {boolean}
68+
*/
69+
@property({ type: Boolean })
70+
mandatory?: boolean;
71+
72+
@property({ type: String })
73+
mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY;
74+
5175
@state()
5276
private _enableRange = false;
5377

@@ -139,7 +163,9 @@ export class UmbPropertyEditorUISliderElement
139163
.max=${this._max}
140164
?enable-range=${this._enableRange}
141165
@change=${this.#onChange}
142-
?readonly=${this.readonly}>
166+
?readonly=${this.readonly}
167+
?required=${this.mandatory}
168+
.requiredMessage=${this.mandatoryMessage}>
143169
</umb-input-slider>
144170
`;
145171
}

src/Umbraco.Web.UI.Client/src/packages/property-editors/toggle/property-editor-ui-toggle.element.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ export class UmbPropertyEditorUIToggleElement
5959
}
6060

6161
#onChange(event: CustomEvent & { target: UmbInputToggleElement }) {
62-
const checked = event.target.checked;
63-
this.value = this.mandatory ? (checked ?? null) : checked;
62+
//checked is never null/undefined
63+
this.value = event.target.checked;
6464
this.dispatchEvent(new UmbChangeEvent());
6565
}
6666

src/Umbraco.Web.UI.Client/src/packages/tags/components/tags-input/tags-input.element.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,14 @@ export class UmbTagsInputElement extends UUIFormControlMixin(UmbLitElement, '')
2323

2424
@property({ type: String })
2525
culture?: string | null;
26+
@property({ type: Boolean })
27+
override required = false;
28+
@property({ type: String })
29+
override requiredMessage = 'This field is required';
2630

2731
@property({ type: Array })
2832
public set items(newTags: string[]) {
29-
const newItems = newTags.filter((x) => x !== '');
33+
const newItems = newTags?.filter((x) => x !== '') || [];
3034
this.#items = newItems;
3135
super.value = this.#items.join(',');
3236
}

src/Umbraco.Web.UI.Client/src/packages/tags/property-editors/tags/property-editor-ui-tags.element.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,22 @@ import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
99

1010
import '../../components/tags-input/tags-input.element.js';
1111
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
12+
import { UMB_VALIDATION_EMPTY_LOCALIZATION_KEY, UmbFormControlMixin } from '@umbraco-cms/backoffice/validation';
1213

1314
/**
1415
* @element umb-property-editor-ui-tags
1516
*/
1617
@customElement('umb-property-editor-ui-tags')
17-
export class UmbPropertyEditorUITagsElement extends UmbLitElement implements UmbPropertyEditorUiElement {
18-
private _value: Array<string> = [];
19-
18+
export class UmbPropertyEditorUITagsElement
19+
extends UmbFormControlMixin<Array<string>, typeof UmbLitElement, undefined>(UmbLitElement, undefined)
20+
implements UmbPropertyEditorUiElement
21+
{
2022
@property({ type: Array })
21-
public set value(value: Array<string>) {
22-
this._value = value || [];
23+
public override set value(value: Array<string>) {
24+
super.value = value || [];
2325
}
24-
public get value(): Array<string> {
25-
return this._value;
26+
public override get value(): Array<string> {
27+
return super.value as string[];
2628
}
2729

2830
/**
@@ -33,6 +35,10 @@ export class UmbPropertyEditorUITagsElement extends UmbLitElement implements Umb
3335
*/
3436
@property({ type: Boolean, reflect: true })
3537
readonly = false;
38+
@property({ type: Boolean })
39+
mandatory?: boolean;
40+
@property({ type: String })
41+
mandatoryMessage = UMB_VALIDATION_EMPTY_LOCALIZATION_KEY;
3642

3743
@state()
3844
private _group?: string;
@@ -61,6 +67,10 @@ export class UmbPropertyEditorUITagsElement extends UmbLitElement implements Umb
6167
});
6268
}
6369

70+
protected override firstUpdated() {
71+
this.addFormControlElement(this.shadowRoot!.querySelector('umb-tags-input')!);
72+
}
73+
6474
#onChange(event: CustomEvent) {
6575
this.value = ((event.target as UmbTagsInputElement).value as string).split(',');
6676
this.dispatchEvent(new UmbChangeEvent());
@@ -72,6 +82,8 @@ export class UmbPropertyEditorUITagsElement extends UmbLitElement implements Umb
7282
.culture=${this._culture}
7383
.items=${this.value}
7484
@change=${this.#onChange}
85+
?required=${!!this.mandatory}
86+
.requiredMessage=${this.mandatoryMessage}
7587
?readonly=${this.readonly}></umb-tags-input>`;
7688
}
7789
}

0 commit comments

Comments
 (0)