question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Observable (Subject-like) inputs for components and directives

See original GitHub issue

Which @angular/* package(s) are relevant/related to the feature request?

core

Description

There’re scenarios when a component’s or directive’s input change triggers some reactive pipeline. Moreover, some pipelines are triggered by a combination of inputs responding to change in any of them.

The simplest use case looks like this:

@Component({
  selector: 'app-movie'
})
export class MovieComponent implements OnDestroy {
  private readonly id$ = new ReplaySubject<string>(1);

  @Input()
  set id(value: string) {
    this.id$.next(value);
  }
  
  readonly movie$ = this.id$.pipe(switchMap(id => this.collection.find(id)));
  
  constructor(
    private readonly collection: MovieCollection,
  ) {}
  
  ngOnDestroy() {
    this.id$.complete();
  }
}

In order to get input as a stream of changes, we have to

  1. Add property containing some Subject, typically ReplaySubject for inputs without initial value or BehaviorSubject for inputs with an initial value;
  2. Use setter for input property and push next value to that Subject;
  3. Don’t forget to clean up - implement OnDestroy and complete the Subject.
  4. Repeat for every input of such kind.

Proposed solution

The solution to this problem is to allow using Subjects as input values:

@Component({
  selector: 'app-movie'
})
export class MovieComponent {
  @Input()
  readonly id = new ReplaySubject<number>(1);
  
  readonly movie$ = this.id.pipe(switchMap(id => this.collection.find(id)));
  
  constructor(
    private readonly collection: MovieCollection,
  ) {}
}

Basically, any object implementing NextObserver should be a legit value. Implementing CompletionObserver should be optional.

Such inputs’ Subjects must be completed automatically when the component/directive is destroyed.

Is may also require a special syntax for such sort of inputs:

<app-movie {id}="123"></app-movie>

Alternatives considered

An alternative may include the usage of a special implementation of Subject, like EventEmitter for outputs:

@Component({
  selector: 'app-movie'
})
export class MovieComponent {
  @Input()
  readonly id = new InputSubject<number>(/* optional initial value */);
  
  readonly movie$ = this.id.pipe(switchMap(id => this.collection.find(id)));
  
  constructor(
    private readonly collection: MovieCollection,
  ) {}
}

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:10
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

4reactions
mfp22commented, Jul 8, 2022

@jessicajaniuk Do you think it will be addressed within 3 years? If not, to me that is equivalent to rejecting it

3reactions
avchugaevcommented, Jul 6, 2022

@pkozlowski-opensource Thanks for referring me to that comment. What wonders me is that the feature request was open in 2015th 🤯 and no changes since then. For such a long period of time, a lot of boilerplate code has been written 😅

Also, while reading @mgechev’s arguments about RxJS-independent core, I thought “What’s the point of doing this as each real-world app/lib inevitably uses streams? Streams are everywhere - in router, forms, HTTP client, in third-party libraries. It won’t have any impact on real-world apps bundle size”.

Streams are great - they’re declarative and composable. On the other hand, we have imperative lifecycle hooks like OnChanges, and a mixture of both makes code less readable and reliable.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Handling Observables with Structural Directives in Angular
Getting reactive data into the view involves defining the observable in our component and binding it by combining the NgIf directive and ...
Read more >
Best practices for a clean and performant Angular application
When subscribing to observables, always make sure you unsubscribe from them appropriately by using operators like take , takeUntil , etc. Why?
Read more >
How to build reactive Angular Components using Inputs as ...
Implementation. The main goal is to be able to define component inputs as observables and be able to react to their changes by...
Read more >
Angular lifehack: reactive component input properties
Responding to input changes using a reactive approach​​ In that case it would be nicer to model your input as an Observable ,...
Read more >
Use an observable store and a component input with Angular
I came accross the same requirement several times and unfortunately there is no simpler solution as your onChange - subject approach.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found