I’m preparing a presentation on the topic of Angular state management for my colleagues. The main focus of the talk is creating “dumb” components which accept inputs from parent components, render this data in a UI and emit changes in outputs. The important part is that they do not store any state of their own (Just computed properties, and computed
signals in Angular v17+). This helps our team create components that don't have change-detection issues, can't have inconsistencies in state between parent and child components and respect unidirectional data flow.
One of the teams that I will be presenting to is using Angular Forms, which means their components implement ControlValueAccessor
, which means they can also accept values via the writeValue
method. This means that their components do have an internal state, and because they can also accept values from @Input
s, weird bugs can happen, especially when integrating them with our codebase that does not use Angular Forms.
What is the official explanation of why these two approaches are so different?
How can an approach where a component gets values from @Input
s be unified with an approach where it gets values from writeValue
? Is it even possible to create a component that is compatible with Angular Forms, and doesn't contain any state of its own?
Is there a way to implement Angular Forms where the components receive their values via @Input
s (Or input
signals in Angular 17+)?
ChatGPT suggested the following:
@Input() value: any;
writeValue(value: any): void {
this.value = value;
}
But from everything I know about Angular, writing to an @Input
is a very bad idea, and is not even possible with signals in Angular 17+.
I’m preparing a presentation on the topic of Angular state management for my colleagues. The main focus of the talk is creating “dumb” components which accept inputs from parent components, render this data in a UI and emit changes in outputs. The important part is that they do not store any state of their own (Just computed properties, and computed
signals in Angular v17+). This helps our team create components that don't have change-detection issues, can't have inconsistencies in state between parent and child components and respect unidirectional data flow.
One of the teams that I will be presenting to is using Angular Forms, which means their components implement ControlValueAccessor
, which means they can also accept values via the writeValue
method. This means that their components do have an internal state, and because they can also accept values from @Input
s, weird bugs can happen, especially when integrating them with our codebase that does not use Angular Forms.
What is the official explanation of why these two approaches are so different?
How can an approach where a component gets values from @Input
s be unified with an approach where it gets values from writeValue
? Is it even possible to create a component that is compatible with Angular Forms, and doesn't contain any state of its own?
Is there a way to implement Angular Forms where the components receive their values via @Input
s (Or input
signals in Angular 17+)?
ChatGPT suggested the following:
@Input() value: any;
writeValue(value: any): void {
this.value = value;
}
But from everything I know about Angular, writing to an @Input
is a very bad idea, and is not even possible with signals in Angular 17+.
1 Answer
Reset to default 0Use a linked signal, which has an internal state, which get's overriden when a new input is received through @Input
:
value: any = input();
innerValue = linkedSignal(() => this.value());
writeValue(value: any): void {
this.innerValue.set(value);
}
For Older versions of angular:
value: any = input();
innerValue = signal();
constructor() {
effect(() => {
this.innerValue.set(this.value());
}, { allowSignalWrites: true });
}
writeValue(value: any): void {
this.innerValue.set(value);
}
The problem lies in how the end user has written the code @Input
can be used to set the inner state using ngOnChanges
it should not be directly written to @Input
.