I would like to markAsDirty
all the controls inside of a FormGroup
.
The accepted answer is correct for a flat form structure, but does not completely answer the original question. A web page may require nested FormGroups and FormArrays, and we must account for this to create a robust solution.
public markControlsDirty(group: FormGroup | FormArray): void {
Object.keys(group.controls).forEach((key: string) => {
const abstractControl = group.controls[key];
if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
this.markControlsDirty(abstractControl);
} else {
abstractControl.markAsDirty();
}
});
}
instanceof
is not a TypeScript-specific keyword (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) Neither is the class
data type. –
Salaam Found out that Object.keys
can handle this..
Object.keys(this.form.controls).forEach(key => {
this.form.get(key).markAsDirty();
});
For Angular 8+, use the following (based on Michelangelo answer):
Object.keys(this.form.controls).forEach(key => {
this.form.controls[key].markAsDirty();
});
Cannot invoke an expression whose type lacks a call signature. Type 'AbstractControl' has no compatible call signatures.
Does anyone know why? –
Orson For what it's worth, there's another way to do this without having to use Object.keys(...) magic:
for (const field in this.form.controls) { // 'field' is a string
const control = this.form.get(field); // 'control' is a FormControl
}
Object.keys(form).forEach
throws an error that : Element implicitly has an 'any' type because expression of type 'string' can't be used to index type
–
Oquinn The accepted answer is correct for a flat form structure, but does not completely answer the original question. A web page may require nested FormGroups and FormArrays, and we must account for this to create a robust solution.
public markControlsDirty(group: FormGroup | FormArray): void {
Object.keys(group.controls).forEach((key: string) => {
const abstractControl = group.controls[key];
if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
this.markControlsDirty(abstractControl);
} else {
abstractControl.markAsDirty();
}
});
}
instanceof
always work after being transpiled by Typescript? –
Tremolant instanceof
is not a TypeScript-specific keyword (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…) Neither is the class
data type. –
Salaam Seems that get
function is not working anymore for retrieving specific values in your form in Angular 8, so this is how I solved it based on the answer of @Liviu Ilea.
for (const field in this.myForm.controls) { // 'field' is a string
console.log(this.myForm.controls[field].value);
}
Using @Marcos answer I created a function that can be called passing a formGroup as parameter and it marks every formGroup children controls to dirty, just to make it usable from more places around the code putting it inside a service, for example.
public touchAllFormFields(formGroup: FormGroup): void {
Object.keys(formGroup.controls).forEach((key) => {
formGroup.get(key).markAsDirty();
});
}
hope it helps ;)
Object.keys( this.registerForm.controls).forEach(key => {
this.registerForm.controls[key].markAsDirty();
});
This is what working for me
private markFormGroupTouched(formGroup: FormGroup) {
Object.keys(formGroup.controls).forEach((key) => {
const control = formGroup.controls[key];
control.markAsDirty();
if ((control instanceof FormGroup)) {
this.markFormGroupTouched(control);
}
});
}
Here, is my solution to your problem, I'm using for loop with an index, hope this helps.
for (const key of Object.keys(this.forms.controls)) {
this.forms.controls[key].markAsDirty();
}
I was looking for a similar solution for a project with multiple forms having file uploads. I needed to create a Form Data object and copy all fields of form in multiple pages. This worked fine for Angular 11.
const formData : FormData = new FormData();
Object.keys(this.staffForm.controls).forEach(key => {
console.log("Control Key => "+key);
console.log("Control Val => "+this.staffForm.controls[key].value);
formData.append(key, this.staffForm.controls[key].value);
});
Simple Solution to iterate formGroup
controls to get values of each form controls:
formGroup: FormGroup;
this.formGroup = this.formBuilder.group({
control1: new FormControl('value1'),
control2: new FormControl(`value2`),
control3: new FormControl('value3')
});
Object.keys(this.formGroup.controls).forEach(key => {
console.log(this.formGroup.controls[key].value)
});
// Output:
value1
value2
value4
What worked for me is the following:
Object.values(this.myFormGroup.controls).forEach((myFormControl: FormControl) => {
myFormControl.markAsDirty();
});
Not sure why everyone is using Object.keys() instead - .values is more direct.
I create this function to make it* I have a control with name 'order', and pass index to him.
{"conditionGroups": [
{
"order": null,
"conditions": []
}
]
}
updateFormData() {
const control = <FormArray>this.form.controls['conditionGroups'];
control.value.map((x,index)=>{
x.order = index;
})
Based on @Keenan Diggs answer I wrote a generic function to traverse a flat or nested form, which accepts an operation to be performed against each form control:
export function traverseForm(
form: FormGroup | FormArray,
fn: ((c: AbstractControl, name: string, path: string) => void),
initialPath: string = '') {
Object.keys(form.controls).forEach((key: string) => {
const abstractControl = form.controls[key];
const path = initialPath ? (initialPath + '.' + key) : key;
fn(abstractControl, key, path);
if (abstractControl instanceof FormGroup || abstractControl instanceof FormArray) {
traverseForm(abstractControl, fn, path);
}
});
}
To be used like this:
const markAsDirty = (ctrl: AbstractControl) => {
if (!(abstractControl instanceof FormGroup) && !(abstractControl instanceof FormArray)) {
abstractControl.markAsDirty();
}
}
traverseForm(form, markAsDirty);
If you don't want to loop over your form control, you can use this way also...
export class NewComponent implements OnInit {
@ViewChild(ClrForm) clrForm: ClrForm;
form: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.buildForm();
}
onFormSubmit() {
if (this.form.invalid) {
this.clrForm.markAsDirty();
return;
}
}
private buildForm() {
this.form = this.formBuilder.group({
sender: [null, [Validators.required]],
sentAt: ['', [Validators.required]]
});
}
}
<form clrForm [formGroup]="form" (submit)="onFormSubmit()">
<div class="clr-form-control clr-row">
<label for="sender" class="clr-control-label clr-col-4">Sender</label>
<div class="clr-control-container clr-col-8">
<app-custom-form-control formControlName="sender"></app-custom-form-control>
</div>
</div>
<clr-date-container>
<label class="clr-col-4">Data wysłania</label>
<input
type="date"
class="clr-col-8"
clrDate
formControlName="sentAt"
/>
</clr-date-container>
<input type="submit" value="Save" />
</form>
you can loop over a FormGroup's children using the _forEachChild()
method of a formGroup. This worked for me for patching values in nested formGroups.
this.myForm.myFormGroup._forEachChild( control => {
control.markAsDirty();
})
What the other answer lack is a way to do it without generating any issues with ts-lint
or typescript
.
Here is a way to do it.
Object.keys(this.form.controls).forEach((key) => {
const control = this.form.get(key);
if (control) {
control.markAsDirty();
//or if we wanted to change the value
//control.setValue(value);
}
});
© 2022 - 2024 — McMap. All rights reserved.
instanceof
always work after being transpiled by Typescript? – Tremolant