For the life of me, it seems like I should be able to create a disabled FormArray. I'm trying to build a view-only parent form (FormArray) with 1-n subarrays (also FormArray). I pass the subarrays down to the child components to initialize their controls (FormControl).
I've tried calling disable()
on the parent form with different options and at different hooks of the life cycle, it throws this exception:
Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.
Here's are a couple examples of some of what I've tried:
ngOnInit
, both create and disable form -> does not disable, throws exceptionngOnInit
create form, in ngAfterViewInit
disable form -> DOES disable but throws exceptionAn older version of forms accepted an options object, and (sadly) this no longer works but would have looked like: new FormArray({ value: myControlsArray, disabled: true })
.
I created a plnkr to model the component hierachy and form.
Does anyone know how to initialize a disabled form?
Edit (answer): I overlooked an important piece of information and clue to the solution. In my use case, I take a saved form value and initialize a new read-only form. Instead of passing the saved form value to the child component, I instead should have created the parent form and its sub-forms and controls.
As noted in the edit, I'm using a saved form value to initialize a new read-only form. Rather than pass the value to the child component to initialize its controls, I solved this in large part by constructing the controls at the same time as the parent form and sub-forms. Doing so I could disable the parent form in ngOnInit
without tripping change detection and still pass the sub-forms down to the child components. Here's an excerpt of what it looked like and the working example:
app.component.ts:
public questions: Array<string[]> = MULTIPLE_RADIOS;
public responses: Array<string[]> = MULTIPLE_RESPONSES;
constructor(private _fb: FormBuilder) {}
ngOnInit() {
this.form = this._fb.array([]);
for (let response of this.responses) {
const questionForm = this._fb.array([]);
for (let responseControl of response) {
questionForm.push(this._fb.control(responseControl));
}
this.form.push(questionForm);
}
this.form.disable({ emitEvent: false });
}
app-radio.component.ts:
@Input()
public form: FormArray;
@Input()
public radios: string[];
constructor(private _fb: FormBuilder) {}
ngOnChanges() {
// same component used to create a live form
// in this case, its parent (app-question.component) gives
// it an empty form, and the child adds the control it needs
if (this.form.length === 0) {
this.form.push(this._fb.control(''));
}
}