Attempting to create a dynamic form that is nested within 2 components. The functionality of the ParentComponent
is running smoothly, but encountering issues with the ChildComponent
. This ChildComponent
utilizes ControlValueAccessor.
Inquiry: The fields are visible in the view, but changes made do not reflect in the parent component. Why is this happening? Are the functions for ControlValueAccessor
implemented correctly?
child.component.html
<ul [formGroup]="fieldsForm">
<li *ngFor="let field of fields">
<label>
<input type="checkbox" [formControlName]="field.$key">
{{field.$key}}
</label>
</li>
</ul>
child.component.ts
import {Component, OnInit, Input, ChangeDetectionStrategy} from '@angular/core';
import {FormGroup, FormBuilder, NG_VALUE_ACCESSOR, ControlValueAccessor} from "@angular/forms";
import {NodeService} from "../../node.service";
@Component({
selector: 'child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() =>ChildComponent), multi: true}
]
})
export class ChildComponent implements OnInit,ControlValueAccessor {
public fieldsForm: FormGroup;
public fields: any = [];
@Input() currentFilter;
@Input() formControlName;
constructor(private fb: FormBuilder, private nodeService: NodeService) {
this.fieldsForm = this.fb.group({});
}
ngOnInit() {
this.getFilterValues(this.formControlName)
.subscribe(fields => {
const acc = {};
this.fields = fields;
fields.forEach(field => acc[field.$key] = [true]);
this.fieldsForm = this.fb.group(acc);
})
)
registerOnChange(fn: (value: any) => void) {
this.fieldsForm.valueChanges.subscribe(fn);
}
registerOnTouched() {}
getFilterValues(type) {
return this.nodeService.getFilterValues(type, {
query: { orderByValue: true, equalTo: 1 }
})
}
}
parent.component.ts
import {Component, OnInit, ChangeDetectionStrategy} from '@angular/core';
import {FormBuilder, FormGroup} from "@angular/forms";
import {Input} from "@angular/core/src/metadata/directives";
import {Subject} from "rxjs";
@Component({
selector: 'filter',
templateUrl: './filter.component.html',
styleUrls: ['./filter.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ParentComponent implements OnInit {
public form: FormGroup;
public groupsForm:Subject<any> = new Subject();
@Input() groups;
@Input() currentFilters;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({})
}
ngOnChanges() {
const acc = {};
this.groups.map(group => {
acc[group] = [];
});
this.groupsForm.next(acc);
}
ngOnInit() {
this.groupsForm.subscribe(groupForm => this.form = this.fb.group(groupForm));
// Detect changes from from
this.form.valueChanges
.subscribe(console.log)
}
}
parent.component.html
<form [formGroup]="form" novalidate>
<fieldset *ngFor="let group of groups">
<child [formControlName]="group" [currentFilter]="currentFilters[group]"></child>
</fieldset>
</form>
Devoted several weeks to developing this form. Explored both nested and single-component approaches. Utilizing ControlValueAccessor
feels like the right path. Any assistance or guidance would be greatly appreciated. Thank you!