UI: Allow empty array in json object edit form.

This commit is contained in:
Igor Kulikov 2023-09-12 13:03:00 +03:00
parent 94dbb1a682
commit ece3540f96
21 changed files with 101 additions and 62 deletions

View File

@ -55,7 +55,7 @@
</button> </button>
<button mat-raised-button color="primary" <button mat-raised-button color="primary"
type="submit" type="submit"
[disabled]="(isLoading$ | async) || attributeFormGroup.invalid || !attributeFormGroup.dirty"> [disabled]="(isLoading$ | async) || invalid() || !attributeFormGroup.dirty">
{{ 'action.add' | translate }} {{ 'action.add' | translate }}
</button> </button>
</div> </div>

View File

@ -72,6 +72,11 @@ export class AddAttributeDialogComponent extends DialogComponent<AddAttributeDia
return originalErrorState || customErrorState; return originalErrorState || customErrorState;
} }
invalid(): boolean {
const value = this.attributeFormGroup.get('value').value;
return !Array.isArray(value) && this.attributeFormGroup.invalid;
}
cancel(): void { cancel(): void {
this.dialogRef.close(false); this.dialogRef.close(false);
} }

View File

@ -33,7 +33,7 @@
</button> </button>
<button mat-button mat-raised-button color="primary" <button mat-button mat-raised-button color="primary"
type="submit" type="submit"
[disabled]="(isLoading$ | async) || attributeFormGroup.invalid || !attributeFormGroup.dirty"> [disabled]="(isLoading$ | async) || invalid() || !attributeFormGroup.dirty">
{{ 'action.update' | translate }} {{ 'action.update' | translate }}
</button> </button>
</div> </div>

View File

@ -62,6 +62,11 @@ export class EditAttributeValuePanelComponent extends PageComponent implements O
return originalErrorState || customErrorState; return originalErrorState || customErrorState;
} }
invalid(): boolean {
const value = this.attributeFormGroup.get('value').value;
return !Array.isArray(value) && this.attributeFormGroup.invalid;
}
cancel(): void { cancel(): void {
this.overlayRef.dispose(); this.overlayRef.dispose();
} }

View File

@ -179,7 +179,7 @@
<tb-json-object-edit <tb-json-object-edit
fxFlex fxFlex
fxLayout="column" fxLayout="column"
required jsonRequired
label="{{ 'gateway.configuration' | translate }}" label="{{ 'gateway.configuration' | translate }}"
formControlName="configurationJson"> formControlName="configurationJson">
</tb-json-object-edit> </tb-json-object-edit>

View File

@ -286,6 +286,7 @@ export class GatewayFormComponent extends PageComponent implements OnInit, OnDes
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: { data: {
jsonValue: config, jsonValue: config,
required: true,
title: this.translate.instant('gateway.title-connectors-json', {typeName: type}) title: this.translate.instant('gateway.title-connectors-json', {typeName: type})
} }
}).afterClosed().subscribe( }).afterClosed().subscribe(

View File

@ -31,6 +31,7 @@ import {
JsonObjectEditDialogComponent, JsonObjectEditDialogComponent,
JsonObjectEditDialogData JsonObjectEditDialogData
} from '@shared/components/dialog/json-object-edit-dialog.component'; } from '@shared/components/dialog/json-object-edit-dialog.component';
import { jsonRequired } from '@shared/components/json-object-edit.component';
@Component({ @Component({
@ -77,7 +78,7 @@ export class GatewayServiceRPCComponent extends PageComponent implements AfterVi
this.commandForm = this.fb.group({ this.commandForm = this.fb.group({
command: [null,[Validators.required]], command: [null,[Validators.required]],
time: [60, [Validators.required, Validators.min(1)]], time: [60, [Validators.required, Validators.min(1)]],
params: ["{}", [Validators.required]], params: [{}, [jsonRequired]],
result: [null] result: [null]
}) })
@ -114,7 +115,8 @@ export class GatewayServiceRPCComponent extends PageComponent implements AfterVi
disableClose: true, disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: { data: {
jsonValue: JSON.parse(this.commandForm.get('params').value) jsonValue: JSON.parse(this.commandForm.get('params').value),
required: true
} }
}).afterClosed().subscribe( }).afterClosed().subscribe(
(res) => { (res) => {

View File

@ -26,14 +26,14 @@
<tb-json-object-edit <tb-json-object-edit
[editorStyle]="{minHeight: '100px'}" [editorStyle]="{minHeight: '100px'}"
fillHeight="true" fillHeight="true"
[required]="settings.attributeRequired" [jsonRequired]="settings.attributeRequired"
label="{{ settings.showLabel ? labelValue : '' }}" label="{{ settings.showLabel ? labelValue : '' }}"
formControlName="currentValue" formControlName="currentValue"
(focusin)="isFocused = true;" (focusin)="isFocused = true;"
(focusout)="isFocused = false;" (focusout)="isFocused = false;"
></tb-json-object-edit> ></tb-json-object-edit>
</fieldset> </fieldset>
<div class="tb-json-input-form__actions" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="20px"> <div class="tb-json-input__actions" fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="20px">
<button mat-button color="primary" <button mat-button color="primary"
type="button" type="button"
[disabled]="!attributeUpdateFormGroup.dirty" [disabled]="!attributeUpdateFormGroup.dirty"
@ -42,7 +42,7 @@
matTooltipPosition="above"> matTooltipPosition="above">
{{ "action.undo" | translate }} {{ "action.undo" | translate }}
</button> </button>
<button mat-button mat-raised-button color="primary" <button mat-raised-button color="primary"
type="submit" type="submit"
[disabled]="attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty"> [disabled]="attributeUpdateFormGroup.invalid || !attributeUpdateFormGroup.dirty">
{{ "action.save" | translate }} {{ "action.save" | translate }}

View File

@ -27,6 +27,10 @@
font-size: 18px; font-size: 18px;
color: #a0a0a0; color: #a0a0a0;
} }
&__actions {
height: 48px;
}
} }
.tb-toast { .tb-toast {

View File

@ -23,13 +23,14 @@ import { UtilsService } from '@core/services/utils.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models'; import { Datasource, DatasourceData, DatasourceType, WidgetConfig } from '@shared/models/widget.models';
import { IWidgetSubscription } from '@core/api/widget-api.models'; import { IWidgetSubscription } from '@core/api/widget-api.models';
import { UntypedFormBuilder, UntypedFormGroup, ValidatorFn, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, ValidatorFn } from '@angular/forms';
import { AttributeService } from '@core/http/attribute.service'; import { AttributeService } from '@core/http/attribute.service';
import { AttributeData, AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models'; import { AttributeData, AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
import { EntityId } from '@shared/models/id/entity-id'; import { EntityId } from '@shared/models/id/entity-id';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
import { createLabelFromDatasource, isDefinedAndNotNull } from '@core/utils'; import { createLabelFromDatasource, isDefinedAndNotNull } from '@core/utils';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { jsonRequired } from '@shared/components/json-object-edit.component';
enum JsonInputWidgetMode { enum JsonInputWidgetMode {
ATTRIBUTE = 'ATTRIBUTE', ATTRIBUTE = 'ATTRIBUTE',
@ -131,7 +132,7 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit {
private buildForm() { private buildForm() {
const validators: ValidatorFn[] = []; const validators: ValidatorFn[] = [];
if (this.settings.attributeRequired) { if (this.settings.attributeRequired) {
validators.push(Validators.required); validators.push(jsonRequired);
} }
this.attributeUpdateFormGroup = this.fb.group({ this.attributeUpdateFormGroup = this.fb.group({
currentValue: [{}, validators] currentValue: [{}, validators]
@ -143,7 +144,7 @@ export class JsonInputWidgetComponent extends PageComponent implements OnInit {
private updateWidgetData(data: Array<DatasourceData>) { private updateWidgetData(data: Array<DatasourceData>) {
if (!this.errorMessage) { if (!this.errorMessage) {
let value = {}; let value = null;
if (data[0].data[0][1] !== '') { if (data[0].data[0][1] !== '') {
try { try {
value = JSON.parse(data[0].data[0][1]); value = JSON.parse(data[0].data[0][1]);

View File

@ -91,7 +91,7 @@
(click)="openEditJSONDialog($event, key, source)"> (click)="openEditJSONDialog($event, key, source)">
<mat-icon>open_in_new</mat-icon> <mat-icon>open_in_new</mat-icon>
</button> </button>
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required')"> <mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('required') && !multipleInputFormGroup.get(key.formId).hasError('invalidJSON')">
{{ getErrorMessageText(key.settings,'required') }} {{ getErrorMessageText(key.settings,'required') }}
</mat-error> </mat-error>
<mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('invalidJSON')"> <mat-error *ngIf="multipleInputFormGroup.get(key.formId).hasError('invalidJSON')">
@ -193,7 +193,7 @@
</button> </button>
<button mat-button mat-raised-button color="primary" type="submit" <button mat-button mat-raised-button color="primary" type="submit"
class="tb-multiple-input--buttons-container__button" class="tb-multiple-input--buttons-container__button"
[disabled]="!multipleInputFormGroup.dirty || multipleInputFormGroup.invalid"> [disabled]="!multipleInputFormGroup.dirty || invalid()">
{{ saveButtonLabel }} {{ saveButtonLabel }}
</button> </button>
</div> </div>

View File

@ -604,7 +604,8 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
} }
public inputChanged(source: MultipleInputWidgetSource, key: MultipleInputWidgetDataKey) { public inputChanged(source: MultipleInputWidgetSource, key: MultipleInputWidgetDataKey) {
if (!this.settings.showActionButtons && !this.isSavingInProgress && this.multipleInputFormGroup.get(key.formId).valid) { const control = this.multipleInputFormGroup.get(key.formId);
if (!this.settings.showActionButtons && !this.isSavingInProgress && (Array.isArray(control.value) || control.valid)) {
this.isSavingInProgress = true; this.isSavingInProgress = true;
const dataToSave: MultipleInputWidgetSource = { const dataToSave: MultipleInputWidgetSource = {
datasource: source.datasource, datasource: source.datasource,
@ -775,6 +776,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: { data: {
jsonValue: formControl.value, jsonValue: formControl.value,
required: key.settings.required,
title: key.settings.dialogTitle, title: key.settings.dialogTitle,
saveLabel: key.settings.saveButtonLabel, saveLabel: key.settings.saveButtonLabel,
cancelLabel: key.settings.cancelButtonLabel cancelLabel: key.settings.cancelButtonLabel
@ -791,4 +793,16 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni
} }
); );
} }
invalid(): boolean {
for (const source of this.sources) {
for (const key of this.visibleKeys(source)) {
const control = this.multipleInputFormGroup.get(key.formId);
if (!Array.isArray(control.value) && control.invalid) {
return true;
}
}
}
return false;
}
} }

View File

@ -89,7 +89,6 @@
<ng-template matExpansionPanelContent> <ng-template matExpansionPanelContent>
<tb-json-object-edit <tb-json-object-edit
[editorStyle]="{minHeight: '100px'}" [editorStyle]="{minHeight: '100px'}"
required
label="{{ 'widget-config.title-style' | translate }}" label="{{ 'widget-config.title-style' | translate }}"
formControlName="titleStyle" formControlName="titleStyle"
></tb-json-object-edit> ></tb-json-object-edit>

View File

@ -22,7 +22,7 @@
class="tb-rule-node-configuration-json" class="tb-rule-node-configuration-json"
formControlName="configuration" formControlName="configuration"
[label]="'rulenode.configuration' | translate" [label]="'rulenode.configuration' | translate"
[required]="required" [jsonRequired]="required"
[fillHeight]="true"> [fillHeight]="true">
</tb-json-object-edit> </tb-json-object-edit>
</div> </div>

View File

@ -33,8 +33,7 @@
<tb-json-object-edit <tb-json-object-edit
formControlName="json" formControlName="json"
label="{{ 'value.json-value' | translate }}" label="{{ 'value.json-value' | translate }}"
validateContent="true" [jsonRequired]="required"
[required]="true"
[fillHeight]="false"> [fillHeight]="false">
</tb-json-object-edit> </tb-json-object-edit>
</fieldset> </fieldset>

View File

@ -26,6 +26,7 @@ import { isNotEmptyStr } from '@core/utils';
export interface JsonObjectEditDialogData { export interface JsonObjectEditDialogData {
jsonValue: object; jsonValue: object;
required?: boolean;
title?: string; title?: string;
saveLabel?: string; saveLabel?: string;
cancelLabel?: string; cancelLabel?: string;
@ -43,6 +44,8 @@ export class JsonObjectEditDialogComponent extends DialogComponent<JsonObjectEdi
saveButtonLabel = this.translate.instant('action.save'); saveButtonLabel = this.translate.instant('action.save');
cancelButtonLabel = this.translate.instant('action.cancel'); cancelButtonLabel = this.translate.instant('action.cancel');
required = this.data.required === true;
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected router: Router, protected router: Router,
@Inject(MAT_DIALOG_DATA) public data: JsonObjectEditDialogData, @Inject(MAT_DIALOG_DATA) public data: JsonObjectEditDialogData,

View File

@ -17,19 +17,23 @@
import { Directive, ElementRef, forwardRef, HostListener, Renderer2, SkipSelf } from '@angular/core'; import { Directive, ElementRef, forwardRef, HostListener, Renderer2, SkipSelf } from '@angular/core';
import { import {
ControlValueAccessor, ControlValueAccessor,
UntypedFormControl,
FormGroupDirective, FormGroupDirective,
NG_VALIDATORS, NG_VALIDATORS,
NG_VALUE_ACCESSOR, NG_VALUE_ACCESSOR,
NgForm, NgForm,
UntypedFormControl,
ValidationErrors, ValidationErrors,
Validator Validator
} from '@angular/forms'; } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core'; import { ErrorStateMatcher } from '@angular/material/core';
import { isObject } from "@core/utils"; import { isObject } from '@core/utils';
@Directive({ @Directive({
selector: '[tb-json-to-string]', selector: '[tb-json-to-string]',
// eslint-disable-next-line @angular-eslint/no-host-metadata-property
host: {
'(blur)': 'onTouched()'
},
providers: [{ providers: [{
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TbJsonToStringDirective), useExisting: forwardRef(() => TbJsonToStringDirective),
@ -48,18 +52,26 @@ import { isObject } from "@core/utils";
export class TbJsonToStringDirective implements ControlValueAccessor, Validator, ErrorStateMatcher { export class TbJsonToStringDirective implements ControlValueAccessor, Validator, ErrorStateMatcher {
private propagateChange = null; private propagateChange = null;
public onTouched = () => {};
private parseError: boolean; private parseError: boolean;
private data: any; private data: any;
@HostListener('input', ['$event.target.value']) input(newValue: any): void { @HostListener('input', ['$event.target.value']) input(newValue: any): void {
try { try {
this.data = JSON.parse(newValue); if (newValue) {
if (isObject(this.data)) { this.data = JSON.parse(newValue);
this.parseError = false; if (isObject(this.data)) {
this.parseError = false;
} else {
this.data = null;
this.parseError = true;
}
} else { } else {
this.parseError = true; this.data = null;
this.parseError = false;
} }
} catch (e) { } catch (e) {
this.data = null;
this.parseError = true; this.parseError = true;
} }
@ -73,9 +85,7 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator,
} }
isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean { isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const originalErrorState = this.errorStateMatcher.isErrorState(control, form); return !!(control && control.invalid && !Array.isArray(control.value) && control.touched);
const customErrorState = !!(control && control.invalid && this.parseError);
return originalErrorState || customErrorState;
} }
validate(c: UntypedFormControl): ValidationErrors { validate(c: UntypedFormControl): ValidationErrors {
@ -87,11 +97,9 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator,
} }
writeValue(obj: any): void { writeValue(obj: any): void {
if (obj) { this.data = obj;
this.data = obj; this.parseError = false;
this.parseError = false; this.render.setProperty(this.element.nativeElement, 'value', obj ? JSON.stringify(obj) : '');
this.render.setProperty(this.element.nativeElement, 'value', JSON.stringify(obj));
}
} }
registerOnChange(fn: any): void { registerOnChange(fn: any): void {
@ -99,5 +107,6 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator,
} }
registerOnTouched(fn: any): void { registerOnTouched(fn: any): void {
this.onTouched = fn;
} }
} }

View File

@ -20,7 +20,7 @@
[fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column"> [fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column">
<div fxLayout="row" fxLayoutAlign="start center" class="tb-json-object-toolbar"> <div fxLayout="row" fxLayoutAlign="start center" class="tb-json-object-toolbar">
<label class="tb-title no-padding" <label class="tb-title no-padding"
[ngClass]="{'tb-required': required, [ngClass]="{'tb-required': jsonRequired,
'tb-readonly': readonly, 'tb-readonly': readonly,
'tb-error': !objectValid}">{{ label }}</label> 'tb-error': !objectValid}">{{ label }}</label>
<span fxFlex></span> <span fxFlex></span>

View File

@ -24,7 +24,14 @@ import {
OnInit, OnInit,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; import {
ControlValueAccessor,
UntypedFormControl,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
Validator,
AbstractControl, ValidationErrors
} from '@angular/forms';
import { Ace } from 'ace-builds'; import { Ace } from 'ace-builds';
import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions'; import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions';
@ -34,6 +41,9 @@ import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
import { guid, isDefinedAndNotNull, isObject, isUndefined } from '@core/utils'; import { guid, isDefinedAndNotNull, isObject, isUndefined } from '@core/utils';
import { ResizeObserver } from '@juggle/resize-observer'; import { ResizeObserver } from '@juggle/resize-observer';
import { getAce } from '@shared/models/ace/ace.models'; import { getAce } from '@shared/models/ace/ace.models';
import { coerceBoolean } from '@shared/decorators/coercion';
export const jsonRequired = (control: AbstractControl): ValidationErrors | null => !control.value ? {required: true} : null;
@Component({ @Component({
selector: 'tb-json-object-edit', selector: 'tb-json-object-edit',
@ -73,27 +83,13 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
@Input() sort: (key: string, value: any) => any; @Input() sort: (key: string, value: any) => any;
private requiredValue: boolean; @coerceBoolean()
get required(): boolean {
return this.requiredValue;
}
@Input() @Input()
set required(value: boolean) { jsonRequired: boolean;
this.requiredValue = coerceBooleanProperty(value);
}
private readonlyValue: boolean;
get readonly(): boolean {
return this.readonlyValue;
}
@coerceBoolean()
@Input() @Input()
set readonly(value: boolean) { readonly: boolean;
this.readonlyValue = coerceBooleanProperty(value);
}
fullscreen = false; fullscreen = false;
@ -245,12 +241,10 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
try { try {
if (isDefinedAndNotNull(this.modelValue)) { if (isDefinedAndNotNull(this.modelValue)) {
this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined : this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined :
(key, objectValue) => { (key, objectValue) => this.sort(key, objectValue), 2);
return this.sort(key, objectValue);
}, 2);
this.objectValid = true; this.objectValid = true;
} else { } else {
this.objectValid = !this.required; this.objectValid = !this.jsonRequired;
this.validationError = 'Json object is required.'; this.validationError = 'Json object is required.';
} }
} catch (e) { } catch (e) {
@ -288,8 +282,8 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va
this.validationError = errorInfo; this.validationError = errorInfo;
} }
} else { } else {
this.objectValid = !this.required; this.objectValid = !this.jsonRequired;
this.validationError = this.required ? 'Json object is required.' : ''; this.validationError = this.jsonRequired ? 'Json object is required.' : '';
} }
this.modelValue = data; this.modelValue = data;
this.propagateChange(data); this.propagateChange(data);

View File

@ -67,7 +67,7 @@
<button matSuffix mat-icon-button (click)="openEditJSONDialog($event)"> <button matSuffix mat-icon-button (click)="openEditJSONDialog($event)">
<mat-icon>open_in_new</mat-icon> <mat-icon>open_in_new</mat-icon>
</button> </button>
<mat-error *ngIf="value.hasError('required')"> <mat-error *ngIf="value.hasError('required') && !value.hasError('invalidJSON')">
{{ (requiredText ? requiredText : 'value.json-value-required') | translate }} {{ (requiredText ? requiredText : 'value.json-value-required') | translate }}
</mat-error> </mat-error>
<mat-error *ngIf="value.hasError('invalidJSON')"> <mat-error *ngIf="value.hasError('invalidJSON')">

View File

@ -15,7 +15,7 @@
/// ///
import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm } from '@angular/forms'; import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm, NgModel } from '@angular/forms';
import { ValueType, valueTypesMap } from '@shared/models/constants'; import { ValueType, valueTypesMap } from '@shared/models/constants';
import { isObject } from '@core/utils'; import { isObject } from '@core/utils';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
@ -23,6 +23,7 @@ import {
JsonObjectEditDialogComponent, JsonObjectEditDialogComponent,
JsonObjectEditDialogData JsonObjectEditDialogData
} from '@shared/components/dialog/json-object-edit-dialog.component'; } from '@shared/components/dialog/json-object-edit-dialog.component';
import { coerceBoolean } from '@shared/decorators/coercion';
@Component({ @Component({
selector: 'tb-value-input', selector: 'tb-value-input',
@ -73,7 +74,8 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor {
disableClose: true, disableClose: true,
panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
data: { data: {
jsonValue: this.modelValue jsonValue: this.modelValue,
required: true
} }
}).afterClosed().subscribe( }).afterClosed().subscribe(
(res) => { (res) => {
@ -115,7 +117,8 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor {
} }
updateView() { updateView() {
if (this.inputForm.valid || this.valueType === ValueType.BOOLEAN) { if (this.inputForm.valid || this.valueType === ValueType.BOOLEAN ||
(this.valueType === ValueType.JSON && Array.isArray(this.modelValue))) {
this.propagateChange(this.modelValue); this.propagateChange(this.modelValue);
} else { } else {
this.propagateChange(null); this.propagateChange(null);