加载数据后设置反应形式(异步) - Angular 5
Posted
技术标签:
【中文标题】加载数据后设置反应形式(异步) - Angular 5【英文标题】:Set reactive form after data loaded (async) - Angular 5 【发布时间】:2018-07-19 01:29:18 【问题描述】:我正在尝试在从 API 加载值后更新表单值。我尝试使用*ngIf
技术,但即使设置了表单,表单也不可见。
我无法分享整个项目,但这里是组件模板和控制器
模板
<div class="page-title">
<h3> Edit news </h3>
</div>
<div class="partner-add-form">
<ng-container *ngIf='newsForm'>
<form action="" [formGroup]='newsForm' (ngSubmit)="onSubmit()">
<div class="row ">
<div class="input-field col s12 tooltip">
<input formControlName='title' [id]="'title'" [type]="'text'">
<label [for]="'title'">Title</label>
<validator-errors [control]='newsForm.get("title")'></validator-errors>
</div>
<div class="input-field col s12 tooltip">
<textarea class="materialize-textarea" formControlName='content' [id]="'content'"></textarea>
<label [for]="'content'">Content</label>
<validator-errors [control]='newsForm.get("content")'></validator-errors>
</div>
<div class="input-field col s12 margin-reset">
<mat-form-field class="full-width">
<mat-select [formControl]='newsForm.controls["partner_id"]'>
<mat-option disabled selected>Categories</mat-option>
<mat-option *ngFor="let partner of partners.data" [value]="partner.id">
partner.name </mat-option>
</mat-select>
</mat-form-field>
<validator-errors [control]='newsForm.controls["partner_id"]'></validator-errors>
</div>
<div class="file-field col s12 input-field">
<div class="btn">
<span>File</span>
<input (change)="fileChangeListener($event)" type="file"> </div>
<div class="file-path-wrapper">
<input class="file-path validate" type="text" placeholder="Upload one or more files"> </div>
</div>
<div class="col s12">
<div class="flex flex-middle flex-center crop-area">
<img-cropper #cropper [image]="data" [settings]="cropperSettings"></img-cropper>
<i class="material-icons">arrow_forward</i>
<div class="result rounded z-depth-1">
<img [src]="data.image " *ngIf="data.image " [width]="cropperSettings.croppedWidth"
[height]="cropperSettings.croppedHeight"> </div>
</div>
</div>
<div class="col s12 form-bottom">
<div class="left">
<button type="button" onclick='window.history.back()' class='btn btn-large waves-effect waves-light '>
<i class="material-icons">keyboard_arrow_left</i>
<span>Back</span>
</button>
</div>
<div class="right">
<button [ngClass]="'disabled':(newsForm['invalid']) || isSubmitting || !data.image " type="submit" class='btn btn-large waves-effect waves-light '>
Submit </button>
</div>
</div>
</div>
</form>
</ng-container>
</div>
控制器
partners;
news = ;
newsForm: FormGroup;
ngOnInit()
setTimeout(() =>
this._dashboardService.routeChangeStarted();
, 0);
this._activatedRoute.params.subscribe(params =>
this.news["id"] = params["id"];
this.getPartners().then(data =>
this.getNews().then(data=>
this.setForm();
)
);
);
setForm()
this.newsForm = this._formBuilder.group(
title: [this.news['title'], [Validators.required]],
content: [this.news['content'], [Validators.required]],
partner_id: [this.news['partner']['id'], [Validators.required]]
);
console.log(new Boolean(this.newsForm));
getPartners()
return Promise((res, rej) =>
setTimeout(() =>
this._dashboardService.progressStarted();
this._dashboardService.routeChangeStarted();
, 0);
this._partnerService.getPartners().subscribe(
partners =>
if (partners.status == 200)
this.partners = partners;
res(partners.data);
else
this._errorActions.errorHandler(partners.status);
setTimeout(() =>
this._dashboardService.progressFinished();
this._dashboardService.routeChangeFinished();
, 0);
,
error =>
this._notificationService.warning("Ups, something went wrong");
);
);
getNews()
setTimeout(() =>
this._dashboardService.routeChangeStarted();
this._dashboardService.progressStarted();
, 0);
return Promise((res, rej) =>
this._newsService.getNews(this.news["id"]).subscribe(
data =>
if (data["status"] == 200)
Object.assign(this.news, data["data"]);
res(this.news);
else
this._errorActions.errorHandler(data["status"]);
setTimeout(() =>
this._dashboardService.progressFinished();
this._dashboardService.routeChangeFinished();
, 0);
,
error =>
this._notificationService.error("Ups, something went wrong");
);
);
有什么问题?设置表单后,它甚至不显示表单本身。从 API 加载数据后,还有其他方法可以设置表单值吗?
【问题讨论】:
【参考方案1】:您可以创建一个单独的函数来用数据填充表单。您可以在从 API 获取数据后调用此函数。
变体 1:setValue
官方角度文档:setValue
使用 setValue,您可以通过传入其属性与 FormGroup 后面的表单模型完全匹配的数据对象来一次分配每个表单控件值。
例子:
updateValues(dataObject: any)
this.heroForm.setValue(
name: this.hero.name,
address: this.hero.addresses[0] || new Address()
);
变体 2:patchValue
官方角度文档:patchValue
使用 patchValue,您可以通过为感兴趣的控件提供键/值对对象来为 FormGroup 中的特定控件分配值。
例子:
updateValues(dataObject: any)
this.heroForm.patchValue(
name: this.hero.name
);
【讨论】:
嗯更好的解决方案,下次遇到这个异步问题时我会这样做【参考方案2】:我遇到过这个问题,我不知道我的解决方案是否是最好的,但它确实有效。该技术是使用loaded: boolean
,您启动到false
,一旦您的数据在您的组件中完全接收,您将其设置为true
这是一个例子:
.html:
<div *ngIf="loaded == false">
<h2>loading ...</h2>
</div>
<div *ngIf="loaded == true">
// your template goes here
</div>
在你的 .ts 中:
loaded: boolean = false;
// your code ....
ngOnInit()
setTimeout(() =>
this._dashboardService.routeChangeStarted();
, 0);
this._activatedRoute.params.subscribe(params =>
this.news["id"] = params["id"];
this.getPartners().then(data =>
this.getNews().then(data=>
this.setForm();
// here is the important part!
this.loaded = true
)
);
);
【讨论】:
【参考方案3】:您可以使用setValue
或patchValue
为您提供异步数据FormGroup
。
private initForm(): void
// For update product
if (this.isUpdate)
this.productService.getProduct(this.id)
.subscribe((product: Product) =>
this.productForm.patchValue(
name: product.name,
price: product.price,
description: product.description,
image: product.image
);
);
// For create product
this.productForm = new FormGroup(
name: new FormControl(null, [
Validators.required,
Validators.minLength(8),
Validators.maxLength(35)
]),
price: new FormControl(null, [
Validators.required,
Validators.min(5000),
Validators.max(50000000),
]),
description: new FormControl(null, [
Validators.required,
Validators.minLength(8),
Validators.maxLength(500)
]),
image: new FormControl(null, Validators.required)
);
【讨论】:
很好...谢谢:) 他们来了【参考方案4】:为了从 Promise 订阅更新表单,我需要手动运行更改检测。这可以通过导入来实现
constructor(private changeDetectorRef: ChangeDetectorRef)
正在运行
this.changeDetectorRef.detectChanges();
【讨论】:
以上是关于加载数据后设置反应形式(异步) - Angular 5的主要内容,如果未能解决你的问题,请参考以下文章
以反应形式设置 Angular 2 FormArray 值?
Angular 8:反应式表单自动映射和 PatchValue 设置成员数据