1

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 @Inputs, 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 @Inputs 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 @Inputs (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 1

1

Use 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.

Sign up to request clarification or add additional context in comments.

1 Comment

I guess there were too many questions in my question up there, and this answer actually does answer one of them. But I was more interested in some explanation of why the Angular team decided to follow two approaches that are so different. Intuitively it would make sense for Angular Forms to work with the existing @Input/@Output mechanism instead of requiring developers to do something completely different.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.