在我的用例中,当用户单击编辑按钮时,Angular对后端进行HTTP调用并检索对象,然后在EDIT表单上填充这些值。用户可以更新或保留这些字段。单击update
按钮时,Angular应该获取表单中所有存在的值并将其发送到后端。因此,这就是问题所在,将值加载到编辑页面表单中并更新了某些字段并保持某些字段不变后,未修改的值变为空。这真的很奇怪
product-edit.component.html
<div *ngIf="productDataAvailable()">
<h2>Update Product</h2>
<br/>
<form [formGroup]="productForm">
<div class="form-group">
<label for="id">Product Id</label>
<input class="form-control" formControlName="id" id="id" type="text" value="{{product.id}}">
<small class="form-text text-muted" id="emailHelp"></small>
</div>
<div class="form-group">
<label for="name">Name</label>
<input class="form-control" formControlName="name" id="name" type="text" value="{{product.name}}">
</div>
<div class="form-group">
<label for="description">Description</label>
<input class="form-control" formControlName="description" height="100" id="description" required type="text"
[value]="product.description" width="200">
</div>
<div class="form-group">
<label for="currency">Price</label> <br/>
<label>
<select (load)="loadCurrencies()" class="form-control" [value]="product.price.currency.symbol" formControlName="currency" id="currency" name="currency">
<option *ngFor="let currency of currencies" value={{currency.id}}>
{{currency.name}}
</option>
</select>
</label>
<input formControlName="price" id="price" required style="margin: 10px; padding: 5px" type="text" [value]="product.price.amount">
</div>
<div class="form-group">
<label>Category:
<select (load)="loadCategories()" class="form-control" formControlName="category" name="category">
<option [value]="category.id" *ngFor="let category of categories">
{{category.name}}
</option>
</select>
</label>
</div>
<div class="form-group">
<label>Manufacturer:
<select (load)="loadManufacturers()" class="form-control" [value]="product.manufacturer.name" formControlName="manufacturer" name="manufacturer">
<option [value]="manufacturer.id" *ngFor="let manufacturer of manufacturers" >
{{manufacturer.name}}
</option>
</select>
</label>
</div>
<button (click)="updateProduct()" class="btn btn-primary" type="submit">Submit</button>
<button (click)="goBack()" class="btn btn-primary" style="margin-left: 30px" type="button">Cancel</button>
</form>
</div>
ProductEditComponent
import {Component, OnInit} from '@angular/core';
import {Product} from '../model/product';
import {ProductService} from '../service/product.service';
import {ActivatedRoute, Router} from '@angular/router';
import {CATEGORY_API_URL, CURRENCY_API_URL, MANUFACTURER_API_URL, PRODUCT_API_URL, SERVER_URL} from '../../../app.constants';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {Price} from '../model/price';
import {Currency} from '../model/currency';
import {Category} from '../../category/model/category';
import {Manufacturer} from '../model/manufacturer';
import {CategoryService} from '../../category/service/category.service';
@Component( {
selector: 'app-product-edit',
templateUrl: './product-edit.component.html',
styleUrls: ['./product-edit.component.css']
} )
export class ProductEditComponent implements OnInit
{
product: Product;
categories: Array<Category>;
currencies: Array<Currency>;
manufacturers: Array<Manufacturer>;
productForm=new FormGroup( {
id: new FormControl( {value: '', disabled: true}, Validators.minLength( 2 ) ),
name: new FormControl( '' ),
description: new FormControl( '' ),
price: new FormControl( '' ),
category: new FormControl( '' ),
currency: new FormControl( '' ),
manufacturer: new FormControl( '' )
} );
constructor(private productService: ProductService,
private categoryService: CategoryService,
private route: ActivatedRoute,
private router: Router)
{
}
ngOnInit()
{
this.getProduct();
this.loadCategories();
this.loadCurrencies();
this.loadManufacturers();
}
productDataAvailable(): boolean
{
return this.product!==undefined;
}
goBack()
{
this.router.navigate( ['/product'] );
}
private getProduct()
{
const id=this.route.snapshot.paramMap.get( 'id' );
const url=SERVER_URL+PRODUCT_API_URL+'find/'+id;
this.productService.getProductDetails( url ).pipe()
.subscribe(
data =>
{
this.product=data;
},
error =>
{
console.log( error );
},
() => console.log( 'getProduct() success' ) );
}
private updateProduct()
{
const id=this.route.snapshot.paramMap.get( 'id' );
const url=SERVER_URL+PRODUCT_API_URL+'update';
const product=new Product();
product.id=Number( id );
product.name=this.productForm.get( 'name' ).value;
product.description=this.productForm.get( 'description' ).value;
const currency=new Currency( this.productForm.get( 'currency' ).value, 'USD', '$' );
product.price=new Price(currency , this.productForm.get( 'price' ).value );
product.category=new Category( this.productForm.get( 'category' ).value );
product.manufacturer=new Manufacturer( this.productForm.get( 'manufacturer' ).value );
product.lastModifiedBy='Admin';
product.lastModifiedDate='Admin';
this.productService.updateProduct( url, product ).subscribe(
value =>
{
console.log( 'Successfully updated product' );
}, error1 =>
{
console.log( 'Failed to update product' );
},
() =>
{
this.router.navigate( ['/product/list'] );
} );
}
private loadCategories()
{
const url=SERVER_URL+CATEGORY_API_URL+'list';
this.categoryService.getCategories( url ).subscribe(
categories =>
{
// @ts-ignore
this.categories=categories;
console.log( 'Successfully loaded categories' );
},
error1 =>
{
console.log( 'Failed to load categories' );
},
() =>
{
} );
}
private loadCurrencies()
{
const url=SERVER_URL+CURRENCY_API_URL+'list';
this.productService.getCurrencies( url ).subscribe(
currencies =>
{
this.currencies=currencies;
},
error1 =>
{
console.log( 'Failed to load currencies' );
},
() =>
{
} );
}
private loadManufacturers()
{
const url=SERVER_URL+MANUFACTURER_API_URL+'list';
this.productService.getManufacturers( url ).subscribe(
manufacturers =>
{
this.manufacturers=manufacturers;
console.log( 'Successfully loaded manufacturers' );
},
error1 =>
{
console.log( 'Failed to load manufacturers' );
},
() =>
{
} );
}
}
角度版本
Angular CLI: 7.3.8
Node: 10.15.0
OS: darwin x64
Angular: 7.2.12
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.13.8
@angular-devkit/build-angular 0.13.8
@angular-devkit/build-optimizer 0.13.8
@angular-devkit/build-webpack 0.13.8
@angular-devkit/core 7.3.8
@angular-devkit/schematics 7.3.8
@angular/cli 7.3.8
@ngtools/webpack 7.3.8
@schematics/angular 7.3.8
@schematics/update 0.13.8
rxjs 6.4.0
typescript 3.2.4
webpack 4.29.0
答案 0 :(得分:3)
据我所知,您已经发出HTTP请求以从服务器中获取数据,但是您没有以正确的方式填充productForm
FormGroup。由于您使用的是反应式表单,因此强烈建议您使用patchValue或setValue来更新FormControl。
对于您的情况,我建议使用patchValue
,因为它比setValue
更灵活。 patchValue
不需要在参数中指定所有FormControl即可更新/设置Form Control的值。
这是您如何使用patchValue的方法。在您的getProduct()
方法上,您可以通过执行以下操作将data
的{{1}}响应中的属性传递到FormGroup中;
getProductDetails()
此外,在模板html上,无需在每个getProduct() {
const id = this.route.snapshot.paramMap.get('id');
const url = SERVER_URL + PRODUCT_API_URL + 'find/' + id;
this.productService.getProductDetails(url).pipe()
.subscribe(
data => {
this.productForm.patchValue({
id: data.id
name: data.name
description: data.description
// other form fields
})
},
error => {
console.log(error);
},
() => console.log('getProduct() success'));
}
或value
上绑定<input>
属性。您可以删除所有这些。这是因为您已经在使用<select>
更新值。
patchValue
当您需要从<div class="form-group">
<label for="name">Name</label>
<input class="form-control" formControlName="name" id="name" type="text">
</div>
<div class="form-group">
<label for="description">Description</label>
<input class="form-control" formControlName="description" height="100" id="description" required type="text" width="200">
</div>
获取数据时,可以使用FormGroup和FormControl上公开的productForm
属性。
value