我该如何从多个子组件绑定表单输入到父组件中定义的数组?



我试图将表单输入从多个子组件(item-input-component)绑定到父组件(add-invoice-component)中定义的数组itemList[]。我想接受三个输入(itemName,quantity,price),从中创建一个Item对象,然后从item-input-component输出Item对象并将其添加到itemList[]。我该怎么做呢?这可能吗?如果没有,有什么好的解决方案呢?

add-invoice-component.html

<form> 
<div>
<h2>Items</h2>
<app-item-input *ngFor="let item of numArray"></app-item-input>
<button (click)="incrementNumOfItems()">Add Item</button>
</div>
</form>

add-invoice-component.ts

import { Component, ElementRef, OnInit, Renderer2 } from '@angular/core';
import { Item } from 'src/app/models/item';
@Component({
selector: 'app-add-invoice',
templateUrl: './add-invoice.component.html',
styleUrls: ['./add-invoice.component.css']
})
export class AddInvoiceComponent implements OnInit {
description!: string;
invoiceDate!: Date;
clientName!: string;
clientAddress!: string;
itemList!: Item[];
numOfItems: number = 2;
numArray: number[] = Array(2).fill(0).map((x,i)=>i);
constructor( private el: ElementRef) { }

ngOnInit(): void {
}
incrementNumOfItems() {
this.numOfItems++;
this.numArray = Array(this.numOfItems).fill(0).map((x,i)=>i);
}

removeItem() {
this.el.nativeElement.remove()
}
}

item-input-component.html

<div class="mb-3 row item">
<div class="col">
<label for="item-name" class="form-label">Item Name</label>
<input type="text" id="item-name" name="clientName" class="form-control">
</div>
<div class="col">
<label for="quantity" class="form-label">Quantity</label>
<input type="text" id="quantity" name="quantity" class="form-control">
</div>
<div class="col">
<label for="price" class="form-label">Price</label>
<input type="text" id="price" name="price" class="form-control">
</div>
<button (click)="removeItem()">Delete Item</button>

item-input-component.ts

import { Component, ElementRef, OnInit , Renderer2} from '@angular/core';
@Component({
selector: 'app-item-input',
templateUrl: './item-input.component.html',
styleUrls: ['./item-input.component.css']
})
export class ItemInputComponent implements OnInit {
itemName!: string;
quantity!: number;
price!: number;
constructor(private el: ElementRef) { }
ngOnInit(): void {
}
removeItem() {
this.el.nativeElement.remove()
}
}

Item.ts

export interface Item {
itemName: string,
quantity: number,
price: number
}

这个问题是关于传递给你的子组件一个对象,要删除你需要使用Output与父组件通信

这个对象将是一个具有属性:itemName, quantity和price的对象-如果你使用[(ngModel)]或FormGroup -并且你使用ReactiveForms-

@Input()element:any
@Output() deleteItem:EventEmitter<any>:new EventEmitter<any>()
<input ... [(ngModel)]="element.clientName">
<input ... [(ngModel)]="element.quantity">
<input ... [(ngModel)]="element.price">
<button (click)="deleteItem.emit(null)">Delete Item</button>

你的父母

<app-item-input *ngFor="let item of list;let i=index"
[element]="list[i]"
(deleteItem)="removeItem(i)"
></app-item-input>

,

list:any[]=this.numArray.map(_=>({
clientName:'',
quantity:0,
price:0
}))
//see that removeItem remove one value of the array.
//**NOT** about your .html
removeItem(index:number) {
this.list.splice(index,1)
}

使用FormArray看起来像

formGroup:FormGroup;
@Input('group') set _group(value)
{
this.formGroup=value as FormGroup
}
@Output() deleteItem:EventEmitter<any>:new EventEmitter<any>()
<form [formGroup]="fromGroup">
<input ... formControlName="clientName">
<input ... formControlName="quantity">
<input ... formControlName="price">
</form>
<button (click)="deleteItem.emit(null)">Delete Item</button>

和父

<app-item-input *ngFor="let item of listFormArray.controls;let i=index"
[group]="listFormArray.at(i)"
(deleteItem)="removeItem(i)"
></app-item-input>
listFormArray:FormArray[]=new FormArray(
this.numArray.map(_=>(new FormGroup({
clientName:new FormControl(null),
quantity:new FormControl(0),
price::new FormControl(0)
})))
)
removeItem(index:number) {
this.formArray.removeAt(index)
}

看起来你对Angular的服务并不熟悉,所以这里有一个例子来告诉你它是如何工作的。

Stackblitz: https://stackblitz.com/edit/angular-ivy-afppeb?file=src/app/item.service.ts


这是一个简单的服务来保存项目,它有添加和删除方法

<<p>项服务/strong>
@Injectable({ providedIn: 'root' })
export class ItemService {
itemList: Item[] = [];
addItem(item: Item) {
this.itemList.push(item);
}
deleteItem(index: number) {
this.itemList.splice(index, 1);
}
}

要访问这个服务,你只需通过任何组件的构造函数注入它:

添加发票组件

export class AddInvoiceComponent {
constructor(private itemService: ItemService) {}
get items() {
return this.itemService.itemList;
}
delete(index: number) {
this.itemService.deleteItem(index);
}
}
<app-item-input></app-item-input>
<h1>Items</h1>
<ng-container *ngFor="let item of items; index as i">
<pre>{{ item | json }}</pre>
<button (click)="delete(i)">Delete</button>
</ng-container>

这里有一个将表单数据转换为对象的简单方法

项目输入组件

export class ItemInputComponent {
formGroup = new FormGroup({
itemName: new FormControl(''),
quantity: new FormControl(0),
price: new FormControl(0),
});
constructor(private itemService: ItemService) {}
onSubmit() {
this.itemService.addItem(this.formGroup.getRawValue());
}
}
<h1>Input</h1>
<form [formGroup]="formGroup" (ngSubmit)="onSubmit()">
<div>
<label>Item Name:</label>
<input type="text" formControlName="itemName" />
</div>
<div>
<label>Quantity:</label>
<input type="number" formControlName="quantity" />
</div>
<div>
<label>Price:</label>
<input type="number" formControlName="price" />
</div>
<button type="submit">Submit</button>
</form>

你可能也想做表单验证,但这只是向你展示服务是如何工作的。

最新更新