![](/img/trans.png)
[英]primeNG p-multiSelect with reactive form setting value dynamically
[英]p-multiselect in a reactive form
我有一個從 json 文件生成的表單。 我確實收到了一個看起來像這樣的 json:
{
"lang": "en",
"name": "user-opinion",
"localName": "My opinion",
"controls": [
{
"name": "hobbies",
"label": "My hobbies",
"value": "",
"type": "select",
"selected": "Select your favorite hobby",
"multi": true,
"selectOptions": [
{ "key": "tennis", "value": "Tennis" },
{ "key": "golf", "value": "Golf" },
{ "key": "bike", "value": "Vélo"}
],
"validators": {}
},
{
"name": "softwares",
"label": "Logiciels",
"value": "",
"type": "select",
"selected": "Choisissez vos IDE",
"multi": true,
"selectOptions": [
{ "key": "eclipse", "value": "Eclipse" },
{ "key": "intellij", "value": "Intellij" },
{ "key": "webstorm", "value": "Webstorm"}
],
"validators": {}
},
{
"name": "comments",
"label": "Comments",
"value": "",
"type": "textarea",
"validators": {}
},
{
"name": "chips",
"label": "Chips",
"values": [],
"type": "chips",
"validators": {}
},
{
"name": "rating",
"label": "Rating",
"rating": 0,
"stars": 5,
"type": "rating",
"validators": {}
},
{
"name": "countries",
"label": "Pays",
"value": "",
"type": "cascadeSelect",
"cascadeSelectOptions": [
{
"name": "Australie",
"code": "AU",
"lvl1elt": [
{
"name": "Nouvelles Galles du Sud",
"lvl2elt": [
{"cname": "Sydney", "code": "A-SY"},
{"cname": "Newcastle", "code": "A-NE"},
{"cname": "Wollongong", "code": "A-WO"}
]
},
{
"name": "Queensland",
"lvl2elt": [
{"cname": "Brisbane", "code": "A-BR"},
{"cname": "Townsville", "code": "A-TO"}
]
}
]
},
{
"name": "Canada",
"code": "CA",
"lvl1elt": [
{
"name": "Quebec",
"lvl2elt": [
{"cname": "Montreal", "code": "C-MO"},
{"cname": "Quebec City", "code": "C-QU"}
]
},
{
"name": "Ontario",
"lvl2elt": [
{"cname": "Ottawa", "code": "C-OT"},
{"cname": "Toronto", "code": "C-TO"}
]
}
]
},
{
"name": "Etats Unis",
"code": "US",
"lvl1elt": [
{
"name": "Californie",
"lvl2elt": [
{"cname": "Los Angeles", "code": "US-LA"},
{"cname": "San Diego", "code": "US-SD"},
{"cname": "San Francisco", "code": "US-SF"}
]
},
{
"name": "Floride",
"lvl2elt": [
{"cname": "Jacksonville", "code": "US-JA"},
{"cname": "Miami", "code": "US-MI"},
{"cname": "Tampa", "code": "US-TA"},
{"cname": "Orlando", "code": "US-OR"}
]
},
{
"name": "Texas",
"lvl2elt": [
{"cname": "Austin", "code": "US-AU"},
{"cname": "Dallas", "code": "US-DA"},
{"cname": "Houston", "code": "US-HO"}
]
}
]
}
],
"validators": {}
}
]
}
這個 json 是通過 API 獲得的,並使用 URL 來檢索它:
ngOnInit(): void {
// loading json response from back
// console.log(this.router.url);
let currentRoute = this.router.url;
this.apiService.getTranslatedForm(currentRoute).subscribe(
(response: any) => {
this.jsonResponse = response
this.buildForm((this.jsonResponse.controls))
},
(error: any) => {
console.log(error)
},
() => {
console.log("Done");
}
)
}
表格的每個元素都是
buildForm(controls: JsonFormControls[]): void {
// we will loop all entries of JsonFormControls objects from the controls array
console.log("controls", controls);
let repeatedInputFormGroup = this.fb.group({});
for (const control of controls) {
// some inputs have one or more validators: input can be required, have a min length, x length...
const controlValidators = [];
// a control has a key and a value.
// example: "validators": { "required": true, "minLength": 10 }
// this snippet is reusable: can be optimized if used in many forms
for (const [key, value] of Object.entries(control.validators)) {
switch (key) {
case 'min':
controlValidators.push(Validators.min(value));
break;
case 'max':
controlValidators.push(Validators.max(value));
break;
case 'required':
if (value) {
controlValidators.push(Validators.required);
}
break;
case 'requiredTrue':
if (value) {
controlValidators.push(Validators.requiredTrue);
}
break;
case 'email':
if (value) {
controlValidators.push(Validators.email);
}
break;
case 'minLength':
controlValidators.push(Validators.minLength(value));
break;
case 'maxLength':
controlValidators.push(Validators.maxLength(value));
break;
case 'pattern':
controlValidators.push(Validators.pattern(value));
break;
case 'nullValidator':
if (value) {
controlValidators.push(Validators.nullValidator);
}
break;
default:
break;
}
}
// we must handle repeated inputs
const formControl = this.fb.control(control.value, controlValidators);
if (control.repeat) {
this.form.addControl(control.name, this.fb.array([formControl]));
} else {
this.form.addControl(control.name, formControl);
}
}
}
對於這個 json,我確實調用了 API 來檢索 JSON。 我遍歷 JSON object 以顯示表單元素。
<!-- creating the form and loop -->
<span *ngIf="form != null">
<h3>{{ jsonResponse.localName }}</h3>
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div *ngFor="let control of jsonResponse.controls">
<div class="mb-3">
<span *ngIf="control.label != '' && control.type !== 'toggle' && control.type !== 'checkbox'">
<label class="form-label">{{ control.label }}</label>
</span>
<!-- for inputs that are not repeatable -->
<span *ngIf="inputTypes.includes(control.type) && control.repeat === false">
<input
[type]="control.type"
formControlName="{{control.name}}"
[value]="control.value"
class="form-control"
/>
</span>
<!-- for inputs that are repeatable -->
<span *ngIf="inputTypes.includes(control.type) && control.repeat === true">
<div formArrayName="{{ control.name }}">
<div
*ngFor="let item of getControls(control.name); let id = index"
class="input-group mb-3">
<input class="form-control" formControlName="{{ id }}"/>
<button
type="button"
class="btn btn-outline-secondary"
(click)="deleteInputItem(control.name, id)">
Remove
</button>
</div>
<button
type="button"
class="btn btn-primary"
(click)="addInputItem(control.name)">
Add entry
</button>
</div>
</span>
<!-- text area -->
<span *ngIf="control.type === 'textarea'">
<textarea
[formControlName]="control.name"
[value]="control.value"
class="form-control"
></textarea>
</span>
<!-- select -->
<span *ngIf="control.type === 'select' && control.multi == false">
<select
[formControlName]="control.name"
class="form-select form-select-lg mb-3">
<option selected>{{ control.selected }}</option>
<option
*ngFor="let option of control.selectOptions"
value="{{ option.key }}"> {{ option.value }}
</option>
</select>
</span>
<!--select multi -->
<span *ngIf="control.type === 'select' && control.multi == true">
<!-- <p>{{ control | json }}</p>-->
<!-- {{ control.selectOptions | json }}-->
<p-multiSelect
[formControlName]="control.name"
[options]="control.selectOptions"
[(ngModel)]="selection"
optionLabel="value"></p-multiSelect>
</span>
<!-- cascade select -->
<span *ngIf="control.type === 'cascadeSelect'">
<!-- the optionGroupChildren depends on object passed in control.cascadeSelectOptions -->
<p-cascadeSelect [options]="control.cascadeSelectOptions"
formControlName = "{{ control.name }}"
optionLabel="cname"
optionGroupLabel="name"
[optionGroupChildren]="['lvl1elt', 'lvl2elt']"
[style]="{'minWidth': '14rem', 'maxWidth': '100%'}"
placeholder="Select a City"
>
<ng-template pTemplate="option" let-option>
<div class="country-item">
<img *ngIf="option.states"/>
<i class="pi pi-compass p-mr-2" *ngIf="option.lvl2elt"></i>
<i class="pi pi-map-marker p-mr-2" *ngIf="option.cname"></i>
<span>{{option.cname || option.name}}</span>
</div>
</ng-template>
</p-cascadeSelect>
</span>
<!-- chips -->
<span *ngIf="control.type === 'chips'">
<p-chips
[(ngModel)]="control.values"
formControlName = "{{ control.name }}"
>
</p-chips>
</span>
<!-- range -->
<span *ngIf="control.type === 'range'">
<p-slider
formControlName = "{{ control.name }}">
</p-slider>
</span>
<span *ngIf="control.type === 'rangeSlide'">
<p-slider
formControlName = "{{ control.name }}"
[min] = "getValue(control.options.min)"
[max] ="getValue(control.options.max)"
[step] ="getValue(control.options.step)"
[range]="true"
>
</p-slider>
</span>
<!-- handling checkboxes -->
<span *ngIf="control.type === 'checkbox'">
<p-checkbox [formControlName]="control.name"
value="{{ control.name }}"></p-checkbox>
<label class="form-check-label"> {{ control.label }}</label>
</span>
<!-- toggle -->
<span *ngIf="control.type === 'toggle'">
<p-inputSwitch
[formControlName]="control.name">
</p-inputSwitch>
</span>
<!-- rating -->
<span *ngIf="control.type === 'rating'">
<p-rating
[cancel]="false"
[formControlName]="control.name"></p-rating>
</span>
<!-- radio buttons -->
<span *ngIf="control.type === 'radio'">
<div class="form-check form-check-inline" *ngFor="let option of control.radioOptions">
<input class="form-check-input"
type="radio" name="{{control.name }}"
id="{{option.key}}-{{option.value}}"
[formControlName]="control.name"
value="{{option.value}}">
<label class="form-check-label" for="{{option.key}}-{{option.value}}">{{option.value}}</label>
</div>
</span>
</div>
</div>
<div>
<button
class="btn btn-primary"
type="submit">
Submit
</button>
</div>
</form>
</span>
<span *ngIf="form != null">
{{ this.form.value | json }}
</span>
我可以使用許多不同的輸入(文本、文本區域...)和primeng 功能,例如p-multiselect;
<span *ngIf="control.type === 'select' && control.multi == true">
<p>{{ control | json }}</p>
{{ control.selectOptions | json }}
<p-multiSelect
[formControlName]="control.name"
[options]="control.selectOptions"
[(ngModel)]="selection"
optionLabel="value"></p-multiSelect>
</span>
</div>
在這個階段,我的不同表單元素是動態顯示的。 我確實有每個輸入的選項。 我的問題是,出於測試目的,我還顯示了表單中的值:
<span *ngIf="form != null">
{{ this.form.value | json }}
</span>
我確實為兩個輸入獲得了我為另一個輸入的值。 在愛好中,我沒有“Eclipse”值,但它設置為兩個輸入的愛好形式值。
一整天的問題不小心解決了。
<span *ngIf="control.type === 'select' && control.multi == true">
<p-multiSelect
[formControlName]="control.name"
[options]="control.selectOptions"
optionLabel="value">
</p-multiSelect>
</span>
使用 ngModel 將我在兩個多選中的選擇添加到數組中。 我只是刪除了這些東西: [(ngModel)]="selection"
現在它就像一個魅力。 當我將它發送到數據庫時,我只需要清理我的表單。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.