javascript - 如何从用户选择的选项绑定到 Angular 表单
问题描述
好吧,比标题复杂一点。。
我正在处理的这个表单是一个表单组。它有几个字段(补充名称、描述和标签),补充名称之一是我需要帮助的,因为我没有处理过像这样的复杂表格,我想把它做好,而不仅仅是提供一个凌乱的补丁工作。
这是发生的预期逻辑顺序
- 例如,用户通过单击该字段添加新的补充并开始输入“肌酸”
- 发出一个查询,根据输入的条目获取产品并返回作为建议提供的 JSON
- 用户点击建议“肌酸”
- 字段已填充并绑定
- 我们通过“添加选项”添加另一个条目,并重复我们要添加的 X 数量的产品。
实际发生了什么
- 用户通过单击字段添加新补充并键入“肌酸”建议请求被发送并填充下拉列表
- 用户点击建议“肌酸”该字段采用该值
- 值实际上是空白
- 用户添加了另一个补充,但之前的选择在该字段中
- 用户清除它并再次键入
- 值为空
需要发生的是用户可以添加 X 数量的补充,并能够从下拉推荐中获取任何选项,并将其添加到表单组数组中,并且不会干扰其他表单组数组值。
我知道这不是绑定表单的正确方法,而且我认为绑定 mat 输入字段以触发查询的方式也不正确,这就是我再次提出问题的原因,而不是提供补丁工作。
组件代码
import { Subscription } from 'rxjs/Subscription';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { UtilitiesService } from '../../utilities/utilities.service';
import { GetSupplementsService } from './get-supplements.service';
@Component({
selector: 'app-supplements',
templateUrl: './supplements.component.html',
styleUrls: ['./supplements.component.css'],
providers: [GetSupplementsService],
})
export class SupplementsComponent implements OnInit {
supplementForm: FormGroup;
queryField: FormControl = new FormControl();
private supplementInventoryResults: Array<ISupplementInventoryResponse>;
private eventForm: FormGroup;
private searchResults: any;
private searchSubscription: Subscription;
private addSupplementSubscription: Subscription;
subcription: Subscription;
constructor (
private bottomSheet: MatBottomSheet,
private _fb: FormBuilder,
private ref: ChangeDetectorRef,
private _utils: UtilitiesService,
private getSupplements: GetSupplementsService,
private router: Router
) { }
public ngOnInit(): void {
this.browsingStackHistory = false;
this.loading = true;
this.supplementForm = this._fb.group({ // the form in question
entryArray: this._fb.array([
this.getUnit()
])
});
this.searchSubscription =
this.queryField.valueChanges
.debounceTime(600)
.distinctUntilChanged()
.switchMap((query) => this.getSupplements.search_supplement_by_category(query))
.subscribe((result) => {
this.searchResults = result;
});
}
public ngOnDestroy(): void {
this.subcription.unsubscribe();
}
private getUnit(): FormGroup {
return this._fb.group({
supplementName: [''],
description: [''],
tags: ['']
});
}
private addUnit(): void {
const control = <FormArray>this.supplementForm.controls['entryArray'];
control.push(this.getUnit());
}
private removeUnit(i: number): void {
const control = <FormArray>this.supplementForm.controls['entryArray'];
control.removeAt(i);
}
private addSupplement(): void { // this will do the post to the service
const supplementObject = {
start: this._utils.get_upload_time(),
data: this.supplementForm.value,
rating: 0
};
}
}
模板
[![<mat-tab label="Add Stack (Test)">
<div style="padding:8px;">
<div fxLayout="row wrap">
<div fxFlex.gt-sm="50%" fxFlex="100">
<h1>Add New Supplements Stack</h1>
<form \[formGroup\]="supplementForm" class="log-workout">
<!-- Start form units array with first row must and dynamically add more -->
<div fxLayout="column" fxLayoutAlign="center center" class="row-height">
<div formArrayName="entryArray">
<mat-divider></mat-divider>
<!-- loop throught units -->
<div *ngFor="let reps of supplementForm.controls.entryArray.controls; let i=index">
<!-- row divider show for every nex row exclude if first row -->
<mat-divider *ngIf="supplementForm.controls.entryArray.controls.length > 1 && i > 0"></mat-divider>
<br>
<!-- group name in this case row index -->
<div \[formGroupName\]="i">
<!-- unit name input field -->
<div class="row">
<mat-form-field class="example-form">
<input matInput placeholder="Supplement Name" \[formControl\]="addSupplementField"
formControlName="supplementName" \[matAutocomplete\]="auto">
<mat-autocomplete #auto="matAutocomplete">
<mat-option *ngFor="let product of supplementResults" \[value\]="product?.product_name">
<img class="example-option-img" aria-hidden \[src\]="product?.product_image" height="25">
{{product?.product_name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
<mat-form-field class="example-form">
<input matInput placeholder="Description" formControlName="description" required>
</mat-form-field>
<mat-form-field class="example-form">
<input matInput placeholder="Tags" formControlName="tags" required>
</mat-form-field>
</div>
<!-- row delete button, hidden if there is just one row -->
<button mat-mini-fab color="warn" *ngIf="supplementForm.controls.entryArray.controls.length > 1"
(click)="removeUnit(i)">
<mat-icon>delete forever</mat-icon>
</button>
</div>
</div>
<!-- New unit button -->
<mat-divider></mat-divider>
<mat-card-actions>
<button mat-raised-button (click)="addUnit()">
<mat-icon>add box</mat-icon>
Add Other Product
</button>
</mat-card-actions>
<button mat-raised-button (click)="addSupplement()">
<mat-icon>add box</mat-icon>
Add Supplement
</button>
</div>
</div>
<!-- End form units array -->
</form>
</div>
</div>
</div>][1]][1]
解决方案
在调用 getUnit() 函数时具有以下内容显然会绑定它,因为它将独立运行且不会发生冲突。
private getUnit(): FormGroup {
const formGroup = this._fb.group({
supplementName: [''],
review: [''],
rating: [''],
notes: [''],
tags: ['']
});
formGroup.get('supplementName').valueChanges
.debounceTime(300)
.distinctUntilChanged()
.switchMap((search) => this.getSupplements.search_supplement_by_category(search))
.subscribe((products) => {
this.supplementResults = products;
});
return formGroup;
}
推荐阅读
- macos - Cocoa - macOS Mojave - openHelpAnchor 不再工作
- nginx - 无法使用 Keycloak 身份验证配置在 Wildfly 中部署的 vaadin 应用程序的 NGINX
- powershell - 将所有日志从各种服务器提取到 excel - 提取额外日志时遇到问题
- logic-programming - 程序的答案集 - 为什么空集不是答案集?
- r - 尝试在 RStudio 中使用 bookdown::publish_book() 发布图书时出错
- python-3.x - 如何使用 Python 查找具有相同 ID 的下一个日期?
- python-2.7 - Matplotlib 图不反映有序的数据集
- php - _remap 函数重定向到不同的 url
- angular - Angular 6:从模型类创建表单
- android - 如果 RecyclerView 存在,为什么要使用 ListView