typescript 加载数据后设置反应形式(异步) - Angular 5
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48686147/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Set reactive form after data loaded (async) - Angular 5
提问by Jamil Alisgenderov
I am trying to update the form values after loading values from an API. I tried using the *ngIf
technique but the form is not visible even when the form is set.
我试图在从 API 加载值后更新表单值。我尝试使用该*ngIf
技术,但即使设置了表单,该表单也不可见。
I am not able to share the full project, but here is the component template and controller
我无法分享完整的项目,但这里是组件模板和控制器
Template
模板
<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>
Controller
控制器
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");
}
);
});
}
What is the problem? It doesn't even show the form itself after setting the form. Is there another way of setting the form values after loading the data from an API?
问题是什么?设置表单后,它甚至不显示表单本身。从 API 加载数据后,是否有另一种设置表单值的方法?
回答by Gregor Doroschenko
You can create a separate function to fill your form with data. You can call this function after getting data from an API.
您可以创建一个单独的函数来用数据填充表单。您可以在从 API 获取数据后调用此函数。
Variant 1: setValue
变体 1: setValue
Official angular documentation: setValue
官方角度文档:setValue
With setValue, you assign every form control value at once by passing in a data object whose properties exactly match the form model behind the FormGroup.
使用 setValue,您可以通过传入属性与 FormGroup 后面的表单模型完全匹配的数据对象来一次性分配每个表单控件值。
Example:
例子:
updateValues(dataObject: any) {
this.heroForm.setValue({
name: this.hero.name,
address: this.hero.addresses[0] || new Address()
});
}
Variant 2: patchValue
变体 2: patchValue
Official angular documentation: patchValue
官方角度文档:patchValue
With patchValue, you can assign values to specific controls in a FormGroup by supplying an object of key/value pairs for just the controls of interest.
使用 patchValue,您可以通过为感兴趣的控件提供键/值对对象,为 FormGroup 中的特定控件分配值。
Example:
例子:
updateValues(dataObject: any) {
this.heroForm.patchValue({
name: this.hero.name
});
}
回答by Flow
i've been confronted to this issue, i don't know if my solution is the best, but it work. The technique is to use a loaded: boolean
that you initiate to false
and once your data fully recived in your component you set it to true
我遇到过这个问题,我不知道我的解决方案是否是最好的,但它有效。该技术是使用loaded: boolean
您发起的false
,一旦您的数据在您的组件中完全接收,您就将其设置为true
here is an exemple :
这是一个例子:
.html:
.html:
<div *ngIf="loaded == false">
<h2>loading ...</h2>
</div>
<div *ngIf="loaded == true">
// your template goes here
</div>
and in your .ts:
并在您的 .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
})
});
});
}
回答by Nguy?n Lam B?u
You can use setValue
or patchValue
which data async for you FormGroup
.
您可以使用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)
});
}