Big question short: Basically what I want to achieve is, to apply readonly attribute to FormControl (textbox), right when it's created programmatically.
Full scenario:
I have a Form that has a FormRow whose elements (FormGroups) are partly generated dynamically. I also have given an option to append a row on click of a button.
I want the FormGroup's FormControls (textboxes) that are generated dynamically to be readonly, but the manually added FormControls should be editable.
How can I achieve this?
<div formArrayName="rows">
<div class="row" *ngFor="let row of detailForm.get('rows').controls; let i = index" [formGroupName]="i">
<div class="col-xs-1 text-center">
<input type="checkbox" [(ngModel)]="detailSelected[i]" [ngModelOptions]="{standalone: true}">
</div>
<div class="col-xs-2">
<input type="text" class="form-control" formControlName="account" (change)="getAccountAssociatedDetails(detailForm.get(['rows', i, 'account']), 'account', i)">
</div>
<div class="col-xs-2">
<input type="text" class="form-control" formControlName="detailNo" (change)="getAccountAssociatedDetails(detailForm.get(['rows', i, 'detailNo']), 'detail', i)">
</div>
<div class="col-xs-4">
<input type="text" class="form-control" readonly formControlName="detailName">
</div>
<div class="col-xs-3">
<input type="text" class="form-control" readonly formControlName="detailCountry">
</div>
</div>
</div>
On change of textbox value, I'm calling the function getAccountAssociatedDetails, as you can see. If there are some details associated with the value entered, I'm replacing that current FormGroup and adding some more FormGroups to the row.
getAccountAssociatedDetails(control: FormControl, type: string, index: number) {
let value = control.value;
if (!!value) {
let form = this.detailForm;
control.setErrors({
'alreadyEntered': null
});
if (type === 'detail') {
if (this.detailAlreadyEnteredManually.detailNo.includes(value)) {
control.setErrors({
'alreadyEntered': true
});
}
} else if (type === 'account') {
if (this.detailAlreadyEnteredManually.accountNumber.includes(value)) {
control.setErrors({
'alreadyEntered': true
});
}
}
// if detail or account is already entered dont call service
if (!control.hasError('alreadyEntered')) {
this.agreementDetailsService.getdetails(value, type)
.subscribe(response => {
let associatedDetailsArray = < Array < any >> response;
if (!!associatedDetailsArray) {
let rows = < FormArray > form.get('rows');
// if search mode is 'detail'
if (type === 'detail') {
if (!this.detailAlreadyEnteredManually.detailNo.includes(value)) {
rows.setControl(index, this.builddetailItem(associatedDetailsArray[0].accountNumber.value, value, associatedDetailsArray[0].detailName, associatedDetailsArray[0].detailCountry));
this.detailAlreadyEnteredManually.detailNo.push(value);
for (let i = 1; i < associatedDetailsArray.length; i++)
rows.insert(index + i, this.builddetailItem(associatedDetailsArray[i].accountNumber.value, value, associatedDetailsArray[i].detailName, associatedDetailsArray[i].detailCountry));
}
//if search mode is 'account'
} else if (type === 'account') {
if (!this.detailAlreadyEnteredManually.accountNumber.includes(value)) {
rows.setControl(index, this.builddetailItem(value, associatedDetailsArray[0].detailNo.value, associatedDetailsArray[0].detailName, associatedDetailsArray[0].detailCountry));
this.detailAlreadyEnteredManually.accountNumber.push(value);
for (let i = 1; i < associatedDetailsArray.length; i++)
rows.insert(index + i, this.builddetailItem(value, associatedDetailsArray[i].detailNo.value, associatedDetailsArray[i].detailName, associatedDetailsArray[i].detailCountry));
}
}
}
},
error => console.log(error));
}
}
}
The last two fields in the FormGroup are readonly by default. Once the user enters something in either of the first two fields and focuses out, the details associated with that value should be fetched, the current FormGroup is replaced and other FormGroups in the generated list are appended. I want all the FormControls in those newly added FormGroups should be readonly. The user can add more fields and the process repeats.