I am struggling to make computed values work with @Input
properties.
Unfortunately, the initial value propagation is not functioning correctly.
https://plnkr.co/edit/1MMpOYOKIouwnNc3uIuy
I have two components: App
(the root component with a template-driven form) and NumComponent
(a child component that simply stores the typed value).
When passing the attribute [useThree]="true"
to NumComponent
, I want to set the default value to '3' in NumComponent
.
However, I am unable to find a way to achieve this without using setTimeout
.
Is there a method to propagate the initial value without relying on setTimeout
?
Edited on 5/5
App component
@Component({
selector: 'my-app',
template: `
<div>
<form novalidate #form="ngForm">
<app-num name="num" ngModel [useThree]="true"></app-num>
</form>
<pre>{{form.value | json}}</pre>
</div>
`
})
export class App {}
NumComponent
export const NumValueAccessor = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NumComponent),
multi: true
};
@Component({
selector: 'app-num',
template: `<input [(ngModel)]="num" type="text" (ngModelChange)="updateValue()" />`,
providers: [NumValueAccessor]
})
export class NumComponent implements ControlValueAccessor {
num = 0;
// I want to set the literal number 3 to the `num` property
// when `useThree` is true.
@Input() useThree = false;
onChange = (_: any) => {};
updateValue(num = this.num) {
this.onChange(String(num));
}
writeValue(value: string): void {
if (this.useThree) {
/**********
* ISSUE
**********/
// This code does not work as expected. Even though the `NumComponent`
// has a value of 3 after running this code, the internal FormComponent
// value of AppComponent remains an empty string.
// this.num = 3;
// this.updateValue(3);
// Using setTimeout resolves this issue. However, I am looking for an
// alternative to achieve this without relying on setTimeout.
// setTimeout(() => {
// this.num = 3;
// this.updateValue(3);
// }, 0);
// Is there any other way to propagate the computed initial value?
this.num = 3;
this.updateValue(3);
/**********
* ISSUE
**********/
this.useThree = false;
return;
}
this.num = Number(value);
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {}
setDisabledState(isDisabled: boolean): void {}
}
It appears that the parent component fails to recognize the propagated value during initialization.