I’m working on a form that manages currencies, with fields for code and label. I’m using the latest Angular features and trying to leverage typed forms.
I have a FormArray inside a FormGroup, which is populated with some pre-filled currency data. The reactive form works as expected—I can add and remove currencies with buttons.
However, I’m facing an issue when trying to access the form control properties in my HTML template to apply validation classes (e.g., showing a valid or invalid state for the input fields). I receive the following error:
NG9: Property 'code' does not exist on type 'AbstractControl<any, any>'. [plugin angular-compiler]
src/app/countries.component.html:34:58:
34 │ [class.is-valid]="currency.code.valid"
Problem:
Here’s the code that triggers the error:
[class.is-valid]="currency.code.valid"
I’ve also tried changing it to:
[class.is-valid]="currency.controls['code'].valid"
Or:
[class.is-valid]="currency.get('code').valid"
But I still get the same error.
My TypeScript Code:
import { CommonModule } from '@angular/common';
import { Component, inject, OnInit } from '@angular/core';
import {
FormArray,
FormBuilder,
FormGroup,
ReactiveFormsModule,
Validators
} from '@angular/forms';
export interface Item {
code: string;
label: string;
}
@Component({
selector: 'app-countries',
standalone: true,
imports: [ReactiveFormsModule, CommonModule],
templateUrl: './countries.component.html',
styleUrl: './countries.component.scss'
})
export class CountriesComponent {
currencyForm: FormGroup;
private formBuilder = inject(FormBuilder);
constructor() {
this.currencyForm = this.formBuilder.group({
currencies: this.formBuilder.array<FormGroup>(
[
{code: 'CAD', label: 'Canadian Dollar'},
{code: 'USD', label: 'United States Dollar'},
{code: 'EUR', label: 'Euro'}
].map(currency => this.createCurrencyFormGroup(currency))
)
});
}
createCurrencyFormGroup(currency: Item) {
return this.formBuilder.group({
code: [currency.code, [Validators.required, Validators.maxLength(3), Validators.minLength(3)]],
label: [currency.label, Validators.required]
});
}
get currencies(): FormArray {
return this.currencyForm.get('currencies') as FormArray;
}
addCurrency() {
const currencyControl = this.createCurrencyFormGroup({code: '', label: ''});
this.currencies.push(currencyControl);
}
removeCurrency(index: number) {
this.currencies.removeAt(index);
}
}
My HTML Code:
<div class="container mt-3">
<form [formGroup]="currencyForm" class="row g-3">
<div class="col-md-5" formArrayName="currencies">
<button type="button" class="btn btn-sm btn-secondary" (click)="addCurrency()">Add Currency</button>
<div *ngFor="let currency of currencies.controls; let idx = index" [formGroupName]="idx">
<div class="row">
<div class="col-4">
<input type="text"
class="form-control"
placeholder="Currency Code"
formControlName="code"
maxlength="3"
[class.is-valid]="currency.get('code').valid"
[class.is-invalid]="currency.get('code').invalid" />
</div>
<div class="col-6">
<input type="text"
class="form-control"
placeholder="Currency Label"
formControlName="label"
[class.is-valid]="currency.get('label').valid"
[class.is-invalid]="currency.get('label').invalid" />
</div>
<div class="col-2">
<button type="button" class="btn btn-danger" (click)="removeCurrency(idx)">Remove</button>
</div>
</div>
</div>
</div>
</form>
</div>
What I've Tried:
- I attempted to access the control using
currency.code.valid,currency.controls['code'].validandcurrency.get('code').valid, but both result in the same error. - It seems like Angular doesn’t recognize the control properties in this way inside the template.
Question:
How can I properly access the form control properties in my FormArray to apply validation classes in the template? What am I doing wrong with my approach to accessing the code and label properties?
Thank you so much
