问题
I have a feature where I need to send dynamically generated input fields on button click.
I have recreated the problem on stackblitz for better understanding.
In that app, when I enter resourceQuantity, the resourceId fields are dynamically generated. My issue is to identify those fields individually and send them on server side on single button click.
This solution I've found on stackblitz is similar, but in my problem I am not removing or adding on button clicks, but (change) event instead.
Here is the HTML code:
<mat-form-field>
<input matInput type="number" formControlName="resourceQuantity" [(ngModel)]="resourceQuantity" placeholder="Enter Resource Quantity" (change)="somethingChanged()"/>
</mat-form-field><br/><br/>
<div>
<ul>
<li *ngFor="let item of counter(resourceQuantity)">
<input matInput type="number" placeholder="Enter Resource Number" formControlName="resourceId"/>
</li>
</ul>
</div>
And here is the TS code:
ngOnInit() {
this.form = new FormGroup({
'employeeId': new FormControl(null, {validators: [Validators.required]}),
'employeeName': new FormControl(null, {validators: [Validators.required]}),
'resourceQuantity': new FormControl(null, {validators: [Validators.required]}),
'resourceId': new FormControl(null, {validators: [Validators.required]})
});
}
somethingChanged() {
console.log(this.resourceQuantity);
}
counter(i: number) {
return new Array(i);
}
Kindly let me know the best solution to my problem. Thanks.
回答1:
Avoid using ngModel
and formControl
together. You can make use of formArray
along with getter functions in your component to get your result.
Edit: I have edited my code to reflect the change you requested by subscribing to valueChanges
on the resourceQuantity
formControl
and generating the formArray
when it detects the change. This creates the resources in real time.
Edit: Do not forget to unsubscribe from valueChanges
to prevent memory leakage. I have updated my Stackblitz to show the same.
Here is a working example on StackBlitz
回答2:
What you have here is a perfect use case for formArray
... the only difference is that you need to add the formControls on the basis on the value which is entered in the resourceQuantity
field.
relevant HTML:
<mat-card>
<form [formGroup]="form" (submit)="add()">
<mat-form-field>
<input matInput type="number" formControlName="employeeId" placeholder="Enter Employee Id" (change)='updateFormString()'/>
</mat-form-field><br/><br/>
<mat-form-field>
<input matInput formControlName="employeeName" placeholder="Enter Employee Name" (change)='updateFormString()'/>
</mat-form-field><br/><br/>
<mat-form-field>
<input matInput type="number" formControlName="resourceQuantity" [(ngModel)]="resourceQuantity" placeholder="Enter Resource Quantity" (change)="somethingChanged()"/>
</mat-form-field><br/><br/>
<!--
<div>
<ul>
<li *ngFor="let item of counter(resourceQuantity)">
<input matInput type="number" placeholder="Enter Resource Number" formControlName="resourceId"/>
</li>
</ul>
</div>
-->
<div fxLayout>
<div>
<button
mat-raised-button
color="accent" [disabled] = "form.invalid">Save
</button>
</div>
</div>
<div formArrayName='resourceId'>
<br/>
<div *ngFor='let item of resourceId.controls; let i = index'>
<input type='text' [formControlName]="i" >
</div>
</div>
</form>
</mat-card>
{{formString}}
relevant TS:
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, Validators, FormArray, FormBuilder } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
form: FormGroup;
resourceQuantity: any;
formString: string;
constructor(private fb: FormBuilder) { }
ngOnInit() {
this.form = this.fb.group({
'employeeId': new FormControl(null, { validators: [Validators.required] }),
'employeeName': new FormControl(null, { validators: [Validators.required] }),
'resourceQuantity': new FormControl(null, { validators: [Validators.required] }),
//'resourceId': new FormControl(null, {validators: [Validators.required]}),
resourceId: this.fb.array([
this.fb.control('test entry default')
])
});
}
updateFormString() {
this.formString = JSON.stringify(this.form.value);
}
somethingChanged() {
for (var i = 1; i < this.resourceQuantity; i++) {
this.addResource();
}
this.updateFormString();
}
get resourceId() {
return this.form.get('resourceId') as FormArray;
}
addResource() {
this.resourceId.push(this.fb.control('test entry additional'));
}
counter(i: number) {
return new Array(i);
}
}
working stackblitz available here
回答3:
I would also set up my employee model to include a Resource array;
import { Resource } from './resource.model';
export interface Employee {
employeeId: number;
employeeName: string;
resourceQuantity: number;
resourceIds: Resource[];
}
Then your resource just needs a id:
export interface Resource {
resourceId: number;
}
回答4:
You should use FormArray
to solve this issue. StackBlitz Demo
1.Change your resourceId
from FormControl
to FormArray
as Follows.
'resourceId': new FormArray([])
2.Change your counter
method to push FormControl
in your FormArray
based on the Resource Quantity, this method calls when the change event triggers in the Resource Quantity. It gets the resourceQuantity
value from the FormGroup
, then clears the FormArray
value. After that, it loops over the index to dynamically create FormControl
and push it in FormArray
counter() {
const index = parseInt(this.form.value.resourceQuantity);
(this.form.controls.resourceId as FormArray).clear();
for(let i = 0; i < index; i++) {
const formControl = new FormControl();
(this.form.controls.resourceId as FormArray).push(formControl);
}
}
3.use getters to access the controls easily
get formControls(): any {
return this.form.controls;
}
get resourceIDControls(): any {
return this.form.controls.resourceId['controls'];
}
4.Change your HTML to loop over FormArray
and set the FormControlName
dynamically.
<div formArrayName="resourceId">
<ul>
<li *ngFor="let item of resourceIDControls; let i = index">
<input matInput type="number" placeholder="Enter Resource Number" [formControlName]="i"/>
</li>
</ul>
</div>
来源:https://stackoverflow.com/questions/56896608/angular-issue-in-adding-dynamically-generated-input-field-data-on-the-change