Correct way to propagate computed value in Angular2
I want to use computed @Input
properties value
But the initial spread value doesn't work.
https://plnkr.co/edit/1MMpOYOKIouwnNc3uIuy
I create a App
(root component with a template driven form) and a NumComponent
(child component that just stores the value entered).
When I pass the attribute NumComponent
as [useThree]="true"
, then I want to set the default '3' toNumComponent
But I cannot find a way without using setTimeout
Is there a way to propagate the initial value without setTimeout?
Edited 5/5
Application 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 set literal number 3 to `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 is not work. after code ran, `NumComponent` has
// value 3 but AppComponent internal FormComponent value
// is '' (empty string)
// this.num = 3;
// this.updateValue(3);
// ran code with `setTimeout` solve this problem. but
// I don't want using setTimeout for this feature.
// setTimeout(() => {
// this.num = 3;
// this.updateValue(3);
// }, 0);
// Is there any way to propagate 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 seems that the parent component does not implement the common meaning during the initialization lifecycle.
source to share
I'm not sure I fully understood the problem, but one possible solution for what you are looking for might be
private _useThree = false;
@Input() set useThree(value: boolean) {
this._useThree = value;
if (this._useThree) {
this.num = 3;
}
}
This way, anytime you want to set the value of an input property useThree
from the parent component, you are actually executing the setter method code defined above.
source to share