具有多选表单更改事件的 Angular6-JSON 架构表单问题



多选的当前实现没有显示<mat-select [formControl]="toppings" multiple>,因为对于类型"array"和"enum",它显示了"复选框"。 因此,我通过以下方式覆盖了该行为:

myCustomWidgets = {
submit: NoneComponent,
checkboxes: CustomMultiSelectComponent 
};

我创建了一个MaterialSelectComponent文件,它是来自"angular6-json-schema-form"的同一文件的副本,然后添加了自定义小部件,如下所示。

<json-schema-form loadExternalAssets="true"
[schema]="formData?.schema"
[form]="formData?.form"
framework="material-design"
[widgets]="myCustomWidgets"
(isValid)="isFormValid($event)"
(onChanges)="onFormChange($event)"
(onSubmit)="onFormSubmit($event)">
</json-schema-form>

我有 4 个元素,一个文本,一个日期,一个单选和一个多选,如下所示。

{
"form": [{
"type": "section",
"htmlClass": "row",
"items": [{
"type": "section",
"htmlClass": "col-xs-6 item-padding",
"items": ["my_text"]
}, {
"type": "section",
"htmlClass": "col-xs-6 item-padding",
"items": ["my_date"]
}
]
}, {
"type": "section",
"htmlClass": "row",
"items": [{
"type": "section",
"htmlClass": "col-xs-6 item-padding",
"items": ["my_multi_select"]
}, {
"type": "section",
"htmlClass": "col-xs-6 item-padding",
"items": ["my_single_select"]
}
]
}
],
"schema": {
"schema": "http://json-schema.org/draft-06/schema#",
"type": "object",
"title": "Form Details",
"description": "",
"properties": {
"my_multi_select": {
"titleSource": "my_multi_select",
"fieldDisplay": "Select More",
"title": "Select More",
"type": "array",
"pattern": null,
"description": "Multi Select",
"format": "",
"required": false,
"multiple": true,
"uniqueItems": true,
"items": {
"type": "string",
"enum": ["A", "B", "C", "D"]
},
"readonly": false
},
"my_text": {
"titleSource": "my_text",
"fieldDisplay": "My Text",
"title": "My Text",
"type": "string",
"pattern": "",
"description": "Enter Text",
"format": "",
"required": true,
"readonly": false
},
"my_date": {
"titleSource": "my_date",
"fieldDisplay": "My Date",
"title": "My Date",
"type": "string",
"pattern": "",
"description": "Enter Date",
"format": "date",
"required": true,
"readonly": false
},
"my_single_select": {
"titleSource": "my_single_select",
"fieldDisplay": "My Single Select",
"title": "My Single Select",
"type": "string",
"pattern": "",
"description": "Enter Date",
"format": "date",
"required": true,
"readonly": false,
"enum": [
"One",
"Two",
"Three",
"Four"
]
}
},
"required": ["my_text", "my_date", "my_single_select"]
},
"data": {
"my_text": "",
"my_date": "",
"my_single_select": "",
"my_multi_select" : []
}
}

现在的问题是它没有捕获方法form-group.functions.ts文件中的数据更改事件,仅用于该"my_multi_select"元素。对于 3 个元素的其余部分,任何更改都会得到回调并捕获值。我已经在json-schema.form.services.ts下面进行了调试,其中所有控件都已注册订阅。在我的 4 个元素中,多选类型为"FormArray",其余元素为"FormControl"。

buildFormGroup() {
this.formGroup = <FormGroup>buildFormGroup(this.formGroupTemplate);
if (this.formGroup) {
this.compileAjvSchema();
this.validateData(this.formGroup.value);
// Set up observables to emit data and validation info when form data changes
if (this.formValueSubscription) { this.formValueSubscription.unsubscribe(); }
this.formValueSubscription = this.formGroup.valueChanges
.subscribe(formValue => this.validateData(formValue));
}
}

表单数组类型订阅或事件发射器是否存在已知错误?

我也尝试使用 ViewChild 来获取值,但我仍然只获取除多选之外的其他值。我仍然不明白,当我选择多个值时,在 UI 中它仍然显示在那里,这意味着它存储在某个地方(可能在 controlValue 中(,但为什么无法访问该值(没有 onchange 事件(?

<json-schema-form #myJsonSchema
loadExternalAssets="true"
[schema]="formData?.schema"
[form]="formData?.form"
framework="material-design"
[widgets]="myCustomWidgets"
(isValid)="isFormValid($event)"
(onChanges)="onFormChange($event)"
(onSubmit)="onFormSubmit($event)">
</json-schema-form>

我团队中的一个人解决了这个问题。请参阅下面的组件代码。 基本上,此处使用复选框代码来发出值。选择更改((方法用于此,如代码所示。我们还遇到了数据绑定的另一个问题,我们已经修复了它以增加价值

import {AbstractControl} from '@angular/forms';
import {buildTitleMap, isArray, JsonSchemaFormService} from 'angular6-json-schema-form';
import {Component, Inject, Input, OnInit, Optional} from '@angular/core';
import {MAT_LABEL_GLOBAL_OPTIONS} from '@angular/material/core';
import {MAT_FORM_FIELD_DEFAULT_OPTIONS} from '@angular/material/form-field';
@Component({
// tslint:disable-next-line:component-selector
selector: 'material-select-widget',
template: `
<mat-form-field
[appearance]="options?.appearance || matFormFieldDefaultOptions?.appearance || 'standard'"
[class]="options?.htmlClass || ''"
[floatLabel]="options?.floatLabel || matLabelGlobalOptions?.float || (options?.notitle ? 'never' : 'auto')"
[hideRequiredMarker]="options?.hideRequired ? 'true' : 'false'"
[style.width]="'100%'">
<mat-label *ngIf="!options?.notitle">{{options?.title}}</mat-label>
<span matPrefix *ngIf="options?.prefix || options?.fieldAddonLeft"
[innerHTML]="options?.prefix || options?.fieldAddonLeft"></span>
<mat-select *ngIf="boundControl"
[attr.aria-describedby]="'control' + layoutNode?._id + 'Status'"
[attr.name]="controlName"
[id]="'control' + layoutNode?._id"
[multiple]="options?.multiple"
[placeholder]="options?.notitle ? options?.placeholder : options?.title"
[required]="options?.required"
[style.width]="'100%'"
[(value)]="selectedValues"
(selectionChange)="selectionChange($event)"
(blur)="options.showErrors = true">
<ng-template ngFor let-selectItem [ngForOf]="selectList">
<mat-option *ngIf="!isArray(selectItem?.items)"
[value]="selectItem?.value">
<span [innerHTML]="selectItem?.name"></span>
</mat-option>
<mat-optgroup *ngIf="isArray(selectItem?.items)"
[label]="selectItem?.group">
<mat-option *ngFor="let subItem of selectItem.items"
[value]="subItem?.value">
<span [innerHTML]="subItem?.name"></span>
</mat-option>
</mat-optgroup>
</ng-template>
</mat-select>
<mat-select *ngIf="!boundControl"
[attr.aria-describedby]="'control' + layoutNode?._id + 'Status'"
[attr.name]="controlName"
[disabled]="controlDisabled || options?.readonly"
[id]="'control' + layoutNode?._id"
[multiple]="options?.multiple"
[placeholder]="options?.notitle ? options?.placeholder : options?.title"
[required]="options?.required"
[style.width]="'100%'"
[value]="controlValue"
(blur)="options.showErrors = true"
(selectionChange)="selectionChange($event)">
<ng-template ngFor let-selectItem [ngForOf]="selectList">
<mat-option *ngIf="!isArray(selectItem?.items)"
[attr.selected]="selectItem?.value === controlValue"
[value]="selectItem?.value">
<span [innerHTML]="selectItem?.name"></span>
</mat-option>
<mat-optgroup *ngIf="isArray(selectItem?.items)"
[label]="selectItem?.group">
<mat-option *ngFor="let subItem of selectItem.items"
[attr.selected]="subItem?.value === controlValue"
[value]="subItem?.value">
<span [innerHTML]="subItem?.name"></span>
</mat-option>
</mat-optgroup>
</ng-template>
</mat-select>
<span matSuffix *ngIf="options?.suffix || options?.fieldAddonRight"
[innerHTML]="options?.suffix || options?.fieldAddonRight"></span>
<mat-hint *ngIf="options?.description && (!options?.showErrors || !options?.errorMessage)"
align="end" [innerHTML]="options?.description"></mat-hint>
</mat-form-field>
<mat-error *ngIf="options?.showErrors && options?.errorMessage"
[innerHTML]="options?.errorMessage"></mat-error>`,
styles: [`
mat-error {
font-size: 75%;
margin-top: -1rem;
margin-bottom: 0.5rem;
}
::ng-deep json-schema-form mat-form-field .mat-form-field-wrapper .mat-form-field-flex
.mat-form-field-infix {
width: initial;
}
`],
})
export class CustomMultiSelectComponent implements OnInit {
formControl: AbstractControl;
controlName: string;
controlValue: any;
controlDisabled = false;
boundControl = false;
options: any;
selectList: any[] = [];
isArray = isArray;
@Input() layoutNode: any;
@Input() layoutIndex: number[];
@Input() dataIndex: number[];
selectedValues = []
constructor(
@Inject(MAT_FORM_FIELD_DEFAULT_OPTIONS) @Optional() public matFormFieldDefaultOptions,
@Inject(MAT_LABEL_GLOBAL_OPTIONS) @Optional() public matLabelGlobalOptions,
private jsf: JsonSchemaFormService
) {
}
ngOnInit() {
this.options = this.layoutNode.options || {};
this.selectList = buildTitleMap(
this.options.titleMap || this.options.enumNames,
this.options.enum, !!this.options.required, !!this.options.flatList
);
this.jsf.initializeControl(this, !this.options.readonly);
if (!this.options.notitle && !this.options.description && this.options.placeholder) {
this.options.description = this.options.placeholder;
}
if (this.boundControl) {
const formArray = this.jsf.getFormControl(this);
for (const selectItem of this.selectList) {
selectItem.checked = formArray.value.includes(selectItem.value);
}
}
this.selectedValues = this.selectList.filter(item => item.checked)
.map(item => item.value);
}
selectionChange(event) {
this.options.showErrors = true;
this.selectList.map(item => item.checked = this.selectedValues.includes(item.value));
if (this.boundControl) {
this.jsf.updateArrayCheckboxList(this, this.selectList);
}
}
}

我希望这对你们有所帮助。任何人都可以使用此代码。我将向 angular6-json-schema-form 项目添加一个 PR。

最新更新