diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html index 659a8156cb..1423000d4a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.html @@ -53,12 +53,20 @@ [readonly]="key.settings.isEditable === 'readonly'" type="number" step="{{key.settings.step}}" + min="{{key.settings.minValue}}" + max="{{key.settings.maxValue}}" (focus)="key.isFocused = true; focusInputElement($event)" (blur)="key.isFocused = false; inputChanged(source, key)"> {{key.settings.icon}} {{key.settings.requiredErrorMessage}} + + {{ 'widgets.input-widgets.min-value-error' | translate:{value: key.settings.minValue} }} + + + {{ 'widgets.input-widgets.max-value-error' | translate:{value: key.settings.maxValue} }} +
@@ -92,6 +100,9 @@ {{key.settings.requiredErrorMessage}} + + {{ 'widgets.input-widgets.invalid-date' | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts index e26600a939..21a8d1d062 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/multiple-input-widget.component.ts @@ -24,7 +24,7 @@ import { UtilsService } from '@core/services/utils.service'; import { TranslateService } from '@ngx-translate/core'; import { DataKey, Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models'; import { IWidgetSubscription } from '@core/api/widget-api.models'; -import { isDefined, isEqual, isUndefined, createLabelFromDatasource } from '@core/utils'; +import { isDefined, isEqual, isUndefined, createLabelFromDatasource, isDefinedAndNotNull } from '@core/utils'; import { EntityType } from '@shared/models/entity-type.models'; import * as _moment from 'moment'; import { FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms'; @@ -62,19 +62,32 @@ interface MultipleInputWidgetDataKeySettings { isEditable: MultipleInputWidgetDataKeyEditableType; disabledOnDataKey: string; dataKeyHidden: boolean; - step: number; - requiredErrorMessage: string; + step?: number; + minValue?: number; + maxValue?: number; + requiredErrorMessage?: string; + invalidDateErrorMessage?: string; + minErrorMessage?: string; + maxErrorMessage?: string; icon: string; inputTypeNumber?: boolean; readOnly?: boolean; disabledOnCondition?: boolean; } +interface MultipleInputWidgetDataKeyErrorMessages { + requiredErrorMessage?: string; + invalidDateErrorMessage?: string; + minErrorMessage?: string; + maxErrorMessage?: string; +} + interface MultipleInputWidgetDataKey extends DataKey { formId?: string; settings: MultipleInputWidgetDataKeySettings; isFocused: boolean; value?: any; + errorMessages?: MultipleInputWidgetDataKeyErrorMessages; } interface MultipleInputWidgetSource { @@ -195,7 +208,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni if (dataKey.units) { dataKey.label += ' (' + dataKey.units + ')'; } - dataKey.formId = (++keyIndex)+''; + dataKey.formId = (++keyIndex) + ''; dataKey.isFocused = false; // For backward compatibility @@ -245,6 +258,14 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni if (key.settings.dataKeyValueType === 'integer') { validators.push(Validators.pattern(/^-?[0-9]+$/)); } + if (key.settings.dataKeyValueType === 'integer' || key.settings.dataKeyValueType === 'double') { + if (isDefinedAndNotNull(key.settings.minValue) && isFinite(key.settings.minValue)) { + validators.push(Validators.min(key.settings.minValue)); + } + if (isDefinedAndNotNull(key.settings.maxValue) && isFinite(key.settings.maxValue)) { + validators.push(Validators.max(key.settings.maxValue)); + } + } const formControl = this.fb.control( { value: key.value, disabled: key.settings.isEditable === 'disabled' || key.settings.disabledOnCondition}, @@ -265,7 +286,11 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni switch (key.settings.dataKeyValueType) { case 'dateTime': case 'date': - value = _moment(keyData[0][1]).toDate(); + if (isDefinedAndNotNull(keyData[0][1]) && keyData[0][1] !== '') { + value = _moment(keyData[0][1]).toDate(); + } else { + value = null; + } break; case 'time': value = _moment().startOf('day').add(keyData[0][1], 'ms').toDate(); @@ -455,7 +480,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni if (tasks.length) { forkJoin(tasks).subscribe( () => { - this.multipleInputFormGroup.reset(undefined, {emitEvent: false}); + // this.multipleInputFormGroup.reset(undefined, {emitEvent: false}); this.multipleInputFormGroup.markAsPristine(); if (this.settings.showResultMessage) { this.ctx.showSuccessToast(this.translate.instant('widgets.input-widgets.update-successful'), @@ -469,7 +494,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } }); } else { - this.multipleInputFormGroup.reset(undefined, {emitEvent: false}); + // this.multipleInputFormGroup.reset(undefined, {emitEvent: false}); this.multipleInputFormGroup.markAsPristine(); } } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 9c36e0ee68..0258408d15 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1991,8 +1991,11 @@ "entity-coordinate-required": "Both fields, latitude and longitude, are required", "entity-timeseries-required": "Entity timeseries is required", "get-location": "Get current location", + "invalid-date": "Invalid Date", "latitude": "Latitude", "longitude": "Longitude", + "min-value-error": "Min value is {{value}}", + "max-value-error": "Max value is {{value}}", "not-allowed-entity": "Selected entity cannot have shared attributes", "no-attribute-selected": "No attribute is selected", "no-datakey-selected": "No datakey is selected",