Angular: Proposal: Input as Observable

Created on 8 Dec 2015  ·  183Comments  ·  Source: angular/angular

Sorry, I'm not good at English.

@Input property values are provided by parent component. The changes come asynchronously.
And if Input property was changed in the child component (it has the property as own property) , its change detector never notice it.

Goal

  • Parent's input data and child's input property should be synchronized.
  • Developers should understand that input properties are changed asynchronously.

    Proposal

@Component({ selector: "child" })
class Child {
  @Input("input") inputValue: Observable<T>;

  ngOnInit() {
    this.inputValue.map((value)=>...);
  }
}

@Component({
  template: `
  <child [input]="valueToChild"></child>
  `
})
class Parent {
  valueToChild: T;
}

Above code does not work. Currently, to receive input as Observable<T>, I must write it like below.

@Component({ selector: "child" })
class Child {
  @Input("input") inputValue: Observable<T>
}

@Component({
  template: `
  <child [input]="valueToChild"></child>
  `
})
class Parent {
  valueToChild: Observable<T> = new Observable<T>((observer)=>{
    ...
    observer.next(val);
  });
}

Example: http://plnkr.co/edit/BWziQygApOezTENdTVp1?p=preview

This works well, but it's not essential. Parent's input data is a simple data originally.

I think this proposal make us happy.

Thanks.

core inputs / outputs feature Needs Design

Most helpful comment

Dear Angular team. Please give us something to look forward to in 2020 :-)

Also @jcomputer solution is exactly what I would be wanting. Not a huge fan of a different decorator name, but maybe it is feasible to add a parameter similar to how @ViewChild has { read }. eg:

@Input({ observable: true }) 
@Input({ asObservable: true }) 
@Input({ asSubject: true })

All 183 comments

Hi @laco0416 - your English is fine, don't worry!

I very much like this idea, and it's something we've discussed before. It also matches up nicely with https://github.com/angular/angular/issues/4062 (Observing view events) and https://github.com/angular/angular/issues/5467 (Observable child events from parents)

It's important to remember that not everybody will want to use Observables (these people are missing out!), so we must provide options for both use cases, and so it's unlikely we'll make @Input() directly into an Observable. I do think that having something like @ObserveInput() might work, and we'll have a discussion _after_ we ship beta about some of these more interesting features I think.

In the meantime, here's a basic (and _very_ experimental!!! do NOT do this for real) implementation of this idea. Is this conceptually what you were thinking? http://plnkr.co/edit/Nvyd9IPBZp9OE2widOcW?p=preview

I think it's a very bad idea to change input properties in a child component. Input properties should be "read-only". Your data should always flow from parent to child (and never in the reverse direction).

@alexpods i believe the idea here is exactly that - its _listening_ to the change in input properties _as_ an Observable, not emitting values upstream, which is absolutely fine as far as I'm concerned.

@robwormald

your English is fine, don't worry!

Thank you! I'm so relieved.

Your @ObserveInput is what just I want!
Also, @Input has no breaking changes. I think it is a very good solution.

@alexpods Me too at all.

its listening to the change in input properties as an Observable, not emitting values upstream, which is absolutely fine as far as I'm concerned.

I think in the same way as Rob.

@laco0416 Ooh, sorry for misunderstanding. The phrase "if Input property was changed in the child component" confused me.

I don't know if I should comment here or if I should open a new issue. Please let me know if I'm adding a request to the wrong place.

I've been trying (but, until now, failing) to write a such a decorator, and then I stumbled upon @robwormald's plunkr, which works _almost_ perfectly (but not quite).

What got me excited by this approach was the fact that it is leveraging into the ngOnChanges lifecycle hook.
What I would like to see is some way for _all_ lifecycle hooks to be exposed as Observables, i.e. as onChanges$: Observable<{[key: string]: SimpleChange}>, onInit$: Observable<{}>, etc.

Having all lifecycle hooks available as Observables will help me Rx all the things ;-)

Any updates on this?

AFAIK, No.
@robwormald do you have any news?

I know this is old, but this would be great! @robwormald Any word on this?

I'd love to provide changing @Input property values as an Observable, just like @robwormald's @ObserveInput decorator does. It's not always feasible to have parent components pass Observables, especially when you're migrating an existing (Angular 1) application. Not being able to "contain" Observables within a single component makes leveraging the power and elegance of RxJS much harder, though.

Unfortunately, Rob wasn't kidding when he said not to use this version of @ObserveInput. The problem I'm running into is that the Observables are created on a "class-level" (if that terminology makes sense) and are hence shared across all instances of the component. This is no good, obviously. Creating the Observables at instantiation time did not work for me, either. It seems Angular doesn't correctly wire up change detection it that case.

Has anyone managed a better implementation of @ObserveInput or is there any news on official support?

@lephyrus While an official @ObserveInput decorator would be a very nice, it's not strictly necessary in order to get an Observable of changing @Input property values. The decorator would simply be very elegant "sugar".

There is already a lifecycle event ngOnChanges. Inside ngOnChanges we can use an rxjs Subject, to create an observable of changes, i.e.:

@Input inputString: string;
private Subject<string> inputString$ = new Subject<string>;

ngOnChanges(changes: { [key: string]: SimpleChange }) {
    if (changes.hasOwnProperty('inputString')) {
        this.inputString$.next(changes['inputString'].currentValue);
    }
}

constructor() {
    inputString$.subscribe(x => {
        console.log('inputString is now', x);
    });
}

Or, if you want something more reusable, you could create a base class that your componentextends:

import { SimpleChange } from '@angular/core';
import { Observable, ConnectableObservable, Observer } from 'rxjs';

export interface TypedSimpleChange<T> {
    previousValue: T;
    currentValue: T;
}

export class ReactiveComponent {
    private changesObserver: Observer<{ [key: string]: SimpleChange }>;
    private changes$: ConnectableObservable<{ [key: string]: SimpleChange }>;

    constructor() {
        this.changes$ = Observable.create((observer: Observer<{ [key: string]: SimpleChange }>) => this.changesObserver = observer).publishReplay(1);
        this.changes$.connect();
    }

    public observeProperty<T>(propertyName: string): Observable<TypedSimpleChange<T>> {
        return this.changes$
            .filter(changes => changes.hasOwnProperty(propertyName))
            .map(changes => changes[propertyName]);
    }

    public observePropertyCurrentValue<T>(propertyName: string): Observable<T> {
        return this.observeProperty<T>(propertyName)
            .map(change => change.currentValue);
    }

    ngOnChanges(changes: { [key: string]: SimpleChange }) {
        this.changesObserver.next(changes);
    }
}

... which could be used as follows:

@Component({
    ...
})
export class YourComponent extends ReactiveComponent {
    @Input() inputString: string;

    constructor() {
        super();
        this.observePropertyCurrentValue<string>('inputString')
            .subscribe(x => console.log('inputString is now', x));
    }
}

I am using this approach until an official @ObserveInput decorator is available.

Thank you, @wmaurer. Your ReactiveComponent is very welcome, and using impeccable code and safe typing to boot - really nice! Importantly, it also behaves well under test and still allows using the OnPush change detection strategy. I'm now happy to wait for the "official sugar". (Also I'm sure I'll learn something when I figure out why you had to use the Observable.create() logic - I haven't found time to look into it yet.) Again: merci gäll! :wink:

@lephyrus you're welcome, gärn gescheh ;-)

I used Observable.create() to get hold of an Observer in order to be able to do a next(). I could have used a Subject which is both an Observable and an Observer, but I believe it's generally bad practice to 'expose' a Subject (Observer).

@laco0416 close in favor of https://github.com/angular/angular/issues/13248 ?

@DzmitryShylovich No. The feature proposed in this issue is read-only and event-driven data passing.

@ObserveInput will be super cool! :+1:

Thank you @wmaurer for a good example. I have one question though. I would like to be able to use an object instead of a string as the observable.

E.g.

@Input() chartConfig: ChartConfig;

constructor(private _reportService: ReportService) {
        super();
             this.observePropertyCurrentValue<string>('chartConfig')
            .subscribe(changedConfig => this.updateChart(changedConfig));
 }

export class ChartConfig {
    public id: string;
    public type: any;
    public data: any;
    public labels: any;
}

However the this.updateChart and the ngOnChanges is not called. How can expand your sample from a simple string to observe an object instead?

@ChrisWorks it should also work with objects:

this.observePropertyCurrentValue<ChartConfig>('chartConfig')
            .subscribe(changedConfig => console.log(changedConfig));

I do this very often, so if this doesn't work, I'd guess there's a problem with the input to your component somewhere.

Hi @wmaurer, thanks for the reply. Would you be able to expand your sample with a working version where you use a "config" object? I simply cant get mine to work. A sample Git repo? :)

@ChrisWorks it really should just work the way it is. observePropertyCurrentValue doesn't differentiate between a string input and an object.
Here's a really old ng2 beta 0 project I made where inputs are of all different types, not just strings:
https://github.com/wmaurer/todomvc-ng2-reactive
e.g. https://github.com/wmaurer/todomvc-ng2-reactive/blob/master/src/app/todo-item/todo-item.component.ts

+1 Such a fundamental use-case, can't believe it hasn't been sorted yet!

I've finally got the best solution and it works without repetition and with AOT compilation :) The secret is to combine @Input() with a second decorator.

The decorator:

import { ReplaySubject } from 'rxjs/ReplaySubject'                                                                                                 

const subjects = new WeakMap()                                                                                                                     

export function ObservableInput() {                                                                                                
  return (target, propertyKey) => {                                                                                                                
    delete target[propertyKey]                                                                                                                     

    Object.defineProperty(target, propertyKey, {                                                                                                   
      set(value) {                                                                                                                                 
        this[propertyKey].next(value)                                                                                                              
      },                                                                                                                                                                                                                            
      get() {                                                                                                                                      
        let subject = subjects.get(this)                                                                                                           
        if (! subject)  {                                                                                                                          
          subject = new ReplaySubject<any>(1)                                                                                                      
          subjects.set(this, subject)                                                                                                              
        }                                                                                                                                          
        return subject                                                                                                                             
      },                                                                                                                                           
    })                                                                                                                                             
  }                                                                                                                                                
}                                                                                                                                                  

Usage:

class SomeComponent {
  @Input() @ObservableInput()                                                                                                                    
  public index: Observable<number>
}                                                                                                               

EDIT: I've now made this a library. Happy to receive ideas to improve it. Adding a new method that compliments an existing @Input with an Observable next. See https://github.com/ohjames/observable-input

If I had to do something like that, I would rather go for a single Subject analog to ngOnChanges: Subject<SimpleChanges>
You could still filter & map to just one specific input if you want to.

1 Subject per input seems a lot without talking about deleting a class prop to create getter & setter and that the type of your input is wrong and doing input = value will in fact emit the value on the observable and you're not completing your subject.

You can find an implementation example of my idea here, the decorator approach is experimental but I think it should be pretty safe to use the inheritance approach (keep in mind I just did it now to show here, it's not used).

@ghetolay it doesn't matter if the subject is completed, when the view is closed there are no more subscriptions to the stream and it can be disposed by the GC. Emitting the value on the observable is basically the point of this. The angular compiler currently doesn't check input property types, hopefully by the time it does something more official will be available ;)

changes$ leaks the BehaviorSubject interface to the component, ideally it should be typed as an Observable<...>, other than that it seems reasonable, if a little more verbose.

As for the issue of many subjects... whether you are using n subjects or 1 you still have n subscriptions. When you have 1 subject you end up adding one map operator and one filter operator to each subscription, the performance overhead of this wouldn't be much less than just using n subjects, it could even be worse.

Ignoring the typing of the input parameters themselves, the decorator based version provides a more typesafe API to consumers of the observables than the SimpleChange types based on any.

@ohjames

when the view is closed there are no more subscriptions to the stream and it can be disposed by the GC

You're assuming all subscriptions will be tied to the view and get the same life cycle as the view. I'm not making any assumption about how the Observable will be consumed.

Emitting the value on the observable is basically the point of this. The angular compiler currently doesn't check input property types, hopefully by the time it does something more official will be available ;)

I meant for user, user can still access and set the property. So it'll set the property as if it was a number except it's typed as an Observable and this will never set the property but make it emit. This is highly confusing to me.

As for the issue of many subjects... whether you are using n subjects or 1 you still have n subscriptions. When you have 1 subject you end up adding one map operator and one filter operator to each subscription, the performance overhead of this wouldn't be much less than just using n subjects, it could even be worse.

Won't go into this kind of debate here because we'll soon lose focus about the main purpose.

I've updated to not expose the Subject and built something up to add typing to changes.
I'm not using a BehaviorSubject but a plain Subject because I'm not seeing those Observable as value holder but as changes over time. If you need access to an input value, the property still exist and you can refers to it synchronously.
I just found a flaw: when using the async pipe, the first value doesn't emit because async pipe will subscribe after the first emit. I'll update my code later to properly handle that case.

Here is the link again: https://stackblitz.com/edit/angular-observableinput?file=observablechanges%2Fimpl.ts

You're assuming all subscriptions will be tied to the view and get the same life cycle as the view. I'm not making any assumption about how the Observable will be consumed.

Okay I see your point, completing the observables will force close all subscriptions, but it's not something that really worries me. In our app 99% of subscriptions happen through the async pipe and in the few that aren't have to be closed manually anyway as they often source in external observables sourced from Redux/etc through combineLatest/switchMap.

Won't go into this kind of debate here because we'll soon lose focus about the main purpose.

Well you raised an invalid criticism so it was necessary to counter that one.

~Also using your class through inheritance won't work, the code generated by the AOT compiler does not call lifecycle methods in parent classes, see https://github.com/angular/angular/issues/12756#issuecomment-260804139, you'll need to add ngOnDestroy() { super.ngOnDestroy() } and another for ngOnChanges to all consumers of the class.~ <-- seems to have been fixed as of Angular 4.4 with certain limitations.

I've review my concern about using the async pipe and since you still have access to the input I don't think the usage was making any sense. If you just want to bind the input value on the template you can just directly bind to the input no need to use any observable and async here. An if you want to compose a new observable from it then you should be able to get exactly what you want easily (probably using startWith somewhere).

So I think my previous statement is ok :

I'm not using a BehaviorSubject but a plain Subject because I'm not seeing those Observable as value holder but as changes over time. If you need access to an input value, the property still exist and you can refers to it synchronously.

This code is highly experimental, it's just some kind of poc and I've only played with it on that stackblitz.
So I shouldn't have said that it was pretty safe sorry and it may don't work with AOT as you've stated.
Just tried it and both approach currently works with AOT (angular v4.3.6, cli v1.4.1).

My main point here is that going from a changes observable containing all inputs changes gives you the possibility to do anything you need using operators: react when any input changed, when just 1 input changed, when an arbitrary number of input changed, when it changed from a specific value to another etc...
You can compose the observable you want.

Also there is only 1 Subject to manage for the implementation and 1 property to use for the user vs 1 per Input.

The thing I could change would be to just emits new values and not SimpleChanges object as user can probably use pair and map to get the same kind of structure as SimpleChange. But currently what we got is SimpleChanges so it would be silly to decompose it just to recompose something similar later.

P.S.:

Well you raised an invalid criticism so it was necessary to counter that one.

invalid to you.

It isn't a personal view point when we are referring to performance, these are objective measurable facts. You feel 3 subjects equals more overhead than 6 additional operators, sure maybe you're right but there's no rational basis for believing that until you make some measurements.

As for reacting to many inputs... sure you can just use switchMap or combineLatest or any of the other operators designed fo working with multiple observables. You are making very bold and sweeping statements about this, if you really want to continue this conversation then let's take it off of this issue tracker.

Here's a version with different drawbacks and advantages but it requires a base class:

import { OnChanges, OnDestroy, SimpleChanges } from '@angular/core'
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/distinctUntilChanged'

export class ChangeObserver implements OnChanges, OnDestroy {
  protected ngChanges = new BehaviorSubject<object>({})

  ngOnChanges(changes: SimpleChanges) {
    const props = { ...this.ngChanges.value }
    for (const propName in changes) {
      props[propName] = changes[propName].currentValue
    }
    this.ngChanges.next(props)
  }

  ngOnDestroy() {
    this.ngChanges.complete()
  }

  changes<K extends keyof this>(key: K): Observable<this[K]>
  changes<V>(key: string): Observable<V>
  changes(key: string) {
    return this.ngChanges.map(props => this.ngChanges.value[key]).distinctUntilChanged()
  }
}

and to use:

class MyComponent extends ChangeObserver {
  @Input() public field: string
  // typescript knows this is Observable<string>
  field$ = this.changes('field')

  @Input() private privField: number
  // typescript can't access private stuff from outside the class so we need to help it out
  privField$ = this.changes<number>('privField')
}

Not sure if I misunderstood the issue, but doesn't the async pipe solve this issue?
[inputVar]="observableValue | async" ..

@najibla you've misunderstood, inputs are not observables so the async pipe does not help.

@ohjames well in my case, it did work using the async pipe for an observable. And when I update the observable value from the parent, the value is reflected in the child component.

@najibla this github issue is about turning @Input properties into observables, this is tenuously related to the case you are describing.

i.e. you shouldn't need to convert input properties into an observable in the view, whether a component responds to the input property changing using an observable or not should be isolated in a component itself. Otherwise you have to change your component's interface if you decide to consume a property as an observable which is at odds with angular's usual "observable first" approach.

@icepeng Actually you haven't got that quite right, this is about turning a standard input into an observable. So the new pattern would actually be:

<app-child [prop]="prop$ | async"></app-child>

... then it provides a way to access prop inside of AppChildComponent as an Observable even though it isn't an observable (or if it was an observable you'd get an observable of observables). Now of course if you had prop$ in the first place as in your example then it might not seem sensible (you can already just pass the observable with inputs now). However it provides a lot of value when the passed input is not already an observable (e.g. an index from an ngFor).

The problem with passing down an observable with an input (which is totally possible right now) is that it wouldn't quite work with OnPush.

@fxck Well you're right that ngOnChanges won't be called when the observable emits (because the input remains the same), but as long as you use the async pipe to subscribe to an observable passed through @Input then OnPush will work fine as the async pipe manually triggers the child component's change detector.

Yes, it was directed towards @icepeng.

@ohjames @fxck I didn't know passing down observable was possible right now, sorry for wrong information.

Since directly passing observable is possible, I'm not sure about @ObserveInput would be useful.
I think if the value that can be changed is not Observable, it is a problem already.
Just a personal opinion.

@icepeng Consider this:

<ng-container *ngFor="value in (values$ | async); let i = index">
  <child-component [value]="value" [index]="i"></child-component>
</ng-container>

How to make index consumable as an observable here without jumping through hoops?

Or also consider you are writing a third-party library and don't want to force consumers of your library to pass observables to your component (many users aren't comfortable with streams and avoid rxjs).

There are many other instances where this is useful.

@ohjames index would be static value for each child-component, so I don't think it has to be observable. However, now I understand why people want this feature. And your solution seems good for writing third-party library.

BehaviorSubject approach seems better, would be nice if Angular core provide @NgChanges() decorator like that.

{
  @NgChanges() ngChanges$: BehaviorSubject<{ prop: string }>
  @Input() prop: string;

  ngOnInit() {
    this.ngChanges$.subscribe(changes => console.log(changes.prop));
  }
}

Is this possible to implement?

A ReplayObservable with buffer length of 1 would be preferable, there's no need for BehaviourSubject's value semantics when you also have access to the property.

As for whether it's possible to implement, check the issue history for many different implementations and options. None are great and some are outright broken, to do it properly we need the linked PR or something similar.

my 2 cents: as object.observe has been depreciated in favour of the proxies, my solution was to extend a proxy (yes you cannot I know, reason why I returned it from the constructor) and then to listen to any key belonging to this object as an Observable through the $get(keyName) method. You can use it with any object, not only angular class one.

import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

/**
 * Extends this class to be able to observe any key affectation
 */
class ObservableProxy {
    private changes: Subject<[PropertyKey, any]> = new Subject<[PropertyKey, any]>();

    constructor() {
        return new Proxy(this, {
            set: (object, key, value) => {
                this.changes.next([key, value]);
                object[key] = value;
                return true;
            }
        });
    }

    public $get<K extends keyof this>(key: K): Observable<this[K]> {
        const value: this[K] = this[key];

        const startWith: Observable<this[K]> = Observable.of(value)
            .filter((initialValue) => // remove this filter if you dont mind receiving an undefined value on subscription
                initialValue !== undefined;
            );

        return this.changes
            .filter(([changedKey]) => {
                return changedKey === key;
            })
            .map(([changedKey, nextValue]) => nextValue)
            .merge(startWith);
    }
}

Example:

class User extends ObservableProxy {
public name: string;
}

const user: User = new User();
user.$get("name").subscribe((value)=> {
console.log(value);
})

user.name = "toto"; // prints console.log("toto")

@robwormald, is there any traction on this issue? It would certainly go a long way towards making things easier to use.

@bryanrideshark The best chance of this being supported is through https://github.com/angular/angular/issues/10185 I think, surprised that PR is not linked to this issue.

This will not happen until after we ship Ivy
On Wed, Feb 21, 2018 at 7:56 AM James Pike notifications@github.com wrote:

@bryanrideshark https://github.com/bryanrideshark The best chance of
this being supported is through #10185
https://github.com/angular/angular/issues/10185 I think, surprised that
PR is not linked to this issue.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/angular/angular/issues/5689#issuecomment-367372931,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAgpkvtGA4w8uHgiz0QsdYwBgqgM2EpAks5tXDyWgaJpZM4Gwr8f
.

Your english is great and your angular is greater.

@pldin601 Your method does not support AOT compiled code, so will lead to huge memory leaks for most people's production code. Check out my observable-input package instead which works well with AOT.

@pldin601 the problem with your code is that it dynamically adds the ngOnDestroy lifecycle method. The AOT compiled code only calls ngOnDestroy if the compiler could statically infer its existence. So your method will only work if every component that uses the decorator also defines an ngOnDestory (it can be empty if not needed). In all other cases it will leak subscriptions, preventing components from being garbage collected.

I guess that will happen after section 3.2 is complete(and hopefully this need is taken into consideration) ?
https://is-angular-ivy-ready.firebaseapp.com/#/status

Will Ivy be part of 7.0.0?

I have implemented a decorator which can bind a property to an observable companion property. It can be used on angular input properties, but also on any other property. It is inspired by the @ObservableInput() decorator of @ohjames, but avoids possible problems caused by type mismatches between property getters and setters by using a different property to provide the Observable.

https://github.com/PSanetra/bind-observable

Example:

class MyClass {

  @BindObservable()
  public myProp: string = 'initialValue';
  public myProp$!: Observable<string>;

}

const myInstance = new MyClass();

myInstance.myProp$.subscribe(console.log);

myInstance.myProp = 'newValue'

This code prints the values 'initialValue' and 'newValue' to the console.

Any update on when this will be released so far the observable-input package seems the like most elegant without breaking anything + no subclassing. @ohjames How stable / well tested is this at this point?

I think official support would be more mature, will guarantee continuous support across versions and smoother dev experience/will encourage developers to go full rxjs* and optimize with on push change detection (this should be a core groundbreaking feature to my opinion)

*without compromizing compatibility with non observable inputs or needing extra boilerplate for hybrid inputs ie: setter calling next on subject

Used observable-input in angular 4, 5 and 7 with and without aot. It seems to work well. I'm pretty sure I vaguely knew what I was doing when I wrote it.

hope they 'll add it in the framework and encourage its usage 2 weekly downloads npm is not enough compared to the advantages it offers xD if they add it I bet people will see that it's simple to follow that approach

I propose following API for async input with user defined observer

decalre function AsyncInput(bindName?:string) : <T extends Observer>(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) => any

users could just use it as

@AsyncInput()
asynchronusProperty1 = new Subject();

@AsyncInput()
asynchronusProperty2 = new ReplySubject(1);

@AsyncInput()
asynchronusProperty3 = new UserObserver(); // where UserObserver implement `Observer` interface

Angular internal can just call observer.next(newValue) whenever value changes.

Don't forget @HostBinding support too!

This should be combined with constructor @Input injection to make it even more awesome. This way we could fix "strictPropertyInitialization" in a very elegant way:

class MyComponent {
  inputData$: Observable<Data>;
  constant: string;

  constructor(
    @Input() inputData$: Observable<Data>,
    @Input() constantString: string
  ) {
    this.inputData$ = inputData$;
    this.constant = constantString;
  }

}

@benneq just worth noting it could be as small as:

class MyComponent {
  constructor(
    @Input() private inputData$: Observable<Data>,
    @Input() private constantString: string,
  ) {}
}

@maxime1992 yep, although you'd need a separate decorator for inputs as observables to distinguish between the case of observables being passed from one component to another.

@benneq @maxime1992 Parameter names are not part of decorator metadata, how do you get it mapped?

@trotyl I guess you could then use @Input('paramName') private myParam: Observable<Data>

@trotyl @benneq yes my bad. Never mind :zipper_mouth_face:

I don't know if someone already posted this solution but this is a fairly good workaround

@ElianCordoba This is not about HTML <input>. It's about angular @Input()

That's a different, but similarly painful issue @ElianCordoba. https://github.com/angular/angular/issues/13248

I think this is a pseudo-requirement. Firstly, the input decorator can accept an Observable type value, secondly, if the component requires an observable as input, it should be explicitly throw error when received a non-observable value instead of quietly convert it to Observable type value.

It is quite similar to implicit type conversion in javascript, may be confused even cause bug and difficult to found.

That's not about silencing wrong input. It's about exposing a common interface across components (which is non-observable input). This gives you the freedom to introduce rx functionality without breaking its interface in the outside world. Another benefit is mainly lifting mutability and internal state since everything will be a transformation of the input which makes on push change detection from that point onwards a no brainer.

On the contrary, exposing, an interface that requires observables sounds clunky and forcing people to provide of(value) just because your component said so sounds weird to me.

Plus it's not about silent conversion, it's an API to subscribe to changes via rxjs. Given angular.http and the router provide observables it's super awkward that input change handling does not, unifying the worlds of callbacks and RxJs requires too much boiler plate.

Not that I don't love some of the clever solutions above, but sometimes just a slight reorganization of the 'standard' way to do it is enough to solve the real problem here which is lack of clarity / clumsiness. Plus I'm still hoping for an 'official' post-ivy way to do this someday.

@Input('isOuterPanel')
set isOuterPanel(value: CheckoutPanelHeaderSettings)
{
    this.inputs.outerPanel$.next(value);
}

@Input('config')
set config(value: CheckoutPanelHeaderSettings)
{
    this.inputs.config$.next(value);
}

// observables for @Inputs
inputs = {
    config$: new BehaviorSubject<CheckoutPanelHeaderSettings>(1),
    outerPanel$: new BehaviorSubject<CheckoutPanelHeaderSettings>(1)
};

Then you can just put something like combineLatest(this.service.magicInput$, this.inputs, config$)...... to combine inputs with RxJS.

Either BehaviorSubject or ReplaySubject works. BehaviorSubject is usually safer and more predictable.

  • BehaviorSubject - use if you have a defaults
  • ReplaySubject - observable won't emit if you forget to set the input value

This not only helps with code clarity but because I'm grouping all the inputs together I can easily see what's a 'pure' observable input by just typing this.inputs. and getting auto-complete.


You can go further with type safety with this (mostly this is just for fun).

// define this globally to 'unwrap' a property 'inputs' with an object of ReplaySubject / BehaviorSubject
export type InputTypes<T extends { inputs: { [key: string]: ReplaySubject<any> | BehaviorSubject<any> } }> = {
    [P in keyof T['inputs']]: T['inputs'][P] extends Observable<infer X> ? X : unknown;
}
// define a local 'InputType' helper above each component
type InputType = InputTypes<CheckoutSmartHeaderComponent>;

Then you don't need to explicitly specify the type of the @Input property.

@Input('config')
set config(value: InputType['config$'])
{
    this.inputs.config$.next(value);
}

I could have made an ObservableInputs interface for the component to enforce inputs but decided not to since it won't compile anyway if you screw this up.

@simeyla Too much boilerplate.

I decided to put my own decorator out there. It's my first npm package so I'm sure there's something I'm missing, but here it is: https://www.npmjs.com/package/@ng-reactive/async-input

Installation

npm install @ng-reactive/async-input --save

Usage

import { Component, Input } from '@angular/core';
import { AsyncInput } from '@ng-reactive/async-input';
import { BehaviorSubject } from 'rxjs';

@Component({
  selector: 'app-hello',
  templateUrl: './hello.component.html',
  styleUrls: ['./hello.component.css']
})
export class HelloComponent {
  @Input() name: string;
  @AsyncInput() name$ = new BehaviorSubject('Default Name');

  constructor() {
    this.name$.subscribe(name => console.log('from async input', name));
  }
}

@mfp22 really nice, I see no reason why something like this shouldn't be built in. FYI, the github link on npm for the package is outdated, it goes to here:

https://github.com/mfp22/async-input/tree/master/projects/async-input

I see this is pretty old issue but the feature is pretty amazing and I'm really exited to see it in Angular.

What is even cooler is that with observable inputs you do not need OnChanges hook - you can use pairwise rxjs operator to get previous and current values of input observable:

@Component({...})
class MyReactiveComponent {
  @ObservableInput() prop: Observable<string>; // Whatever syntax may be...

  // emits [prevValue, currValue] and no OnChanges hook yay!!
  propChanges$ = this.prop.pipe(pairwise());
}

https://github.com/rx-ts/ngrx/blob/master/src/utils/decorators.ts#L56-L124

It's my personal implementation, it works perfectly and pretty awesome, if we can have it build-in, that is really cool.

I've published the solution I've used personally in my projects as a npm package:

https://github.com/futhark/ngx-observable-input

Installation

npm install ngx-observable-input

Usage

...
<image-item [url]="currentImageUrl"></image-item>
import { Component, Input } from "@angular/core";
import { ObservableInput } from "ngx-observable-input";
import { Observable } from "rxjs";

@Component({
    selector: "image-item",
    template: `<img [src]="url$ | async" />`
})
export class GalleryComponent {
    @ObservableInput() @Input("url") public url$: Observable<string>;

    ...
}

I see this is pretty old issue but the feature is pretty amazing and I'm really exited to see it in Angular.

What is even cooler is that with observable inputs you do not need OnChanges hook - you can use pairwise rxjs operator to get previous and current values of input observable:

@Component({...})
class MyReactiveComponent {
  @ObservableInput() prop: Observable<string>; // Whatever syntax may be...

  // emits [prevValue, currValue] and no OnChanges hook yay!!
  propChanges$ = this.prop.pipe(pairwise());
}

This is an issue that has been also bothering me for a while, so I've investigated a little bit and came up with the same solution that you mention here (@gund).

I've implemented a small decorator helper (@ObservableInput) that extends internally the @Input decorator and allows this kind of composition. You can check it out here (also as npm package). I've been testing around with simple examples, but I didn't have the time to use it for extended projects. Any feedback is welcome :)

Here a usage example:

@Component({
  selector: 'app-test',
  template: `<span>{{ message$ | async }}</span>`
})
class TestComponent {
  @ObservableInput<number>('price') price$: Observable<number>;
  @ObservableInput<string>('name') name$: Observable<string>;

  message$ = combineLatest(this.price$, this.name$).pipe(
    map(([price, name]) => `${name} costs {price}`)
  );
}

And this component can be used like this:

<app-test [price]="price"
          [name]="name">
</app-test>

@aleics Are you sure that this is going to work with AOT compiler?

@aleics Are you sure that this is going to work with AOT compiler?

No, not out of the box, of course, since the @Input property is not explicitly defined. But you could define your module with CUSTOM_ELEMENTS_SCHEMA, as when using Web Components, and then it should compile.

This issue has been open for 5 years 🤦‍♂ . I think its necessary to have this to facilitate a reactive programming approach

Ivy is finally here, so I guess someone has time to work on this one? Please-please-please!

Omg I subscribe that this is very much needed. Input data should be emitted as a reactive source, and you have to use workaround to have that working in a ngOnChanges

Really looking forward for this

I realize Angular is open source, but is it wrong or naive of me to think that a project run by Google should be able to resolve heavily starred and requested issues in less than 5 years? Are there are some financial issues that I am not aware of that are preventing Google from hiring more developers to work on Angular?

@etay2000 I don't know, I think it's kind of funny how you can do 75% of things in Angular with rxjs and then for something as fundamental and commonly used as component inputs, all of a sudden you're forced into the procedural world. You've always got this significant piece of your project that can't work with the world of observables, so you're always forced to use boilerplate to glue them back together. You can never quite achieve a fully functional approach to your project. So this issue being open for 4 years reminds me of the lack of pragmatism that drove me away from Angular and into other frameworks, for that it's pretty useful. If you want to use rxjs for everything, maybe cycle.js is a better solution, and if you don't want to be forced to use rxjs at all, maybe Vue is. Having to use observables half the time and not be able to use them the other half just doesn't make any sense. To integrate a very powerful abstraction with a high learning curve and then fail to fully integrate it is just baffling.

I feel like the chain of prioritisation goes like this

requirements of internal google users -> anything to do with compiler being faster -> anything to do with app size being smaller -> anything that doesn't upset newcomers -> what developers actually want

And while the tech leads would say they agree it’s important, the fact is that Igor and Misko tend to think about most problems in terms of template compilation, view bindings, and rendering. No matter what the consumers of Angular are saying is important to them, the solution is always to change the templating system, or write a new renderer, or make the compiler better.

source: https://medium.com/@jeffbcross/jeffs-letter-to-the-angular-team-and-community-5367934a16c9)

Just look at some of the most upvoted issues.

Proposal: Input as Observable #5689

Created 5 years ago, last reply from a relevant team member - 5 years ago, current status unknown.

Support cold event streams in templates #13248

Created 4 years ago, last reply from a relevant team member - 1 years ago, current status - waiting for Ivy to land.

Proposal: Provide Component Lifecycle Hooks as Observables #10185

Created 4 years ago, last reply from a relevant team member - 3 years ago, current status unknown.

Proposal: Need ability to add directives to host elements in component declaration. #8785

Created 4 years ago, last reply from a relevant team member - 2 years ago, current status unknown.

as local-val without *ngIf #15280

Created 4 years ago, last reply from a relevant team member - 2 years ago, current status unknown.

Support for Dynamic Content Projection #8563

Created 4 years ago, last reply from a relevant team member - 3 years ago, current status unknown.

ng-content default content #12530

Created 4 years ago, last reply from a relevant team member - never, current status unknown.

Then there are things like components features, that would allow higher order components, then there are of course many more most upvoted issues, but these I hoped would be addressed (that is, addressed, not necessarily expecting them to get implemented right away after Ivy), because they have to do with everyday usage of the framework AND reactivity, which, I think none would argue, is what most people are using (given ngrx is the most popular state management lib).

My app is full of half baked (simply due to technical limitations, some can only be properly done in core) “polyfills” and hacks to most of these issues, in hope that I’ll one day be able to drop in an angular native replacement. But somehow it doesn’t seem to be coming.

So yeah, let’s say that a blog post addressing state of some of the biggest reactivity / developers experience related issue would be reallllllllly appreciated.

How about we try to code a first version of this feature ourselves? I’m
dying of boredom during the covid thingy, who wants to join me?

Multiple people did already, eg. https://github.com/insidewhy/observable-input

The problem with most of these is that to do them efficiently, you need to modify compiler or other internal parts of angular.

That doesn’t count. I mean let’s do a proper contribution to the angular
core. After all, we do have the source code available. Actually, I don’t think that we will even need to touch the compiler in this case.

@ganqqwerty I tried to implement it inside of Angular before I wrote that library. Angular is extremely complicated though. To be fair to it, the code is far more readable and understandable than React and its crazy five-hundred-line-long-functions, but it's "sophisticated". And I still would have been happy to put in the effort to make that implementation if I thought that it was worthwhile. But I don't see it as worthwhile for precisely the reasons @fxck iterated above. The Angular team don't listen to the community, they constantly obsess over optimisations and performance without caring about the usability of Angular in general. I don't care about a framework that performs well when it forces me to implement boilerplate for simple problems that were demonstrated five years ago. So I decided to stop caring about Angular, implement the minimal effort I needed to support the projects I was already working on and avoid it wherever and whenever possible for all future projects.

This isn't just a problem with Angular I think, but with many offerings from Google. This issue and the others that @fxck listed above are just more examples of endemic problems at Google. If you look at Dart or GoLang you'll also see developers raise very well-known commonly-faced problems and for the issues to languish open for 5+ years.

I agree this should be added, but wow, the hate on this thread is a bit much, I mean we're talking about adding something that saves a few lines of code. You can have observables inputs now with a setter decorated with @Input and your own subject you push values on to:

https://github.com/angular/angular/issues/5689#issuecomment-507001686

If that's too much boilerplate, we already have some simple third party options:

https://github.com/Futhark/ngx-observable-input

I'm happy with Angular's development, and certainly wouldn't abandon the amazingly full featured and reliable framework because of such a petty (albeit desirable) feature

The general problem is mainly from the perspective of how people see it. For somebody, it's a few lines of code and it looks pretty simple to change/add anything, but in reality, there is a lot of bigger scope and many side effects. All of them have to be taken into account and as always, the line of topics is long and everything has some cost price, added value, and priority.

I would like to point out that I personally don't necessarily expect all of these issues to be resolved immediately.

But I would hope, that now, that Ivy is out of the way and been out in the wild for a while, some sort of official update on, say, top 25 upvoted issues, would be published.

I mean, I don't find it possible for a project of this size not to have in project management considered priority and some sort of plan for all of the top 25 (or whatever) upvoted issues. Most of these even have an effort tag. Just make a blog post, let community know that you know about these and you have some sort of plan for them.

I certainly wouldn't abandon Angular either, for all of its shortcomings I still like it much better than all the other alternatives. But I think it's fair to say its been lacking in "community relations management" (on github specificaly).

// edit

Would you good people mind filling this poll? Given your current situation and all things considered, which of these issues affect you the most / would improve your developer experience the most https://forms.gle/cprhx239kuqwWd5M8

@fxck Thanks for writing that. I was beginning to wonder if everyone had just accepted the fact that the Angular team will do what they want, when they want. While that is certainly their right, I also think it is necessary for people to call them out when they continually ignore developers voices. I agree that I don't think anyone expects immediate resolution of issues, but ignoring them for 4-5 years or just waiting until the issue is automatically locked seems really unprofessional for any project, let alone a Google run project. They bought some time by adding 'Fixed by Ivy' tags to a bunch of open issues, then followed that up by doing nothing.

I certainly wouldn't abandon Angular either, for all of its shortcomings I still like it much better than all the other alternatives. But I think it's fair to say its been lacking in "community relations management" (on github specificaly).

I think that sentence sums up my thoughts perfectly.

@chriszrc I didn't really interpret anything in this thread as 'hate'. More like people finally venting their frustrations with Angular regularly ignoring issues for years at a time. It is not even about this issue specifically, it is more about the principle of maintaining some form of community interaction. Is the Angular team considered so far superior to anyone else that they feel they can ignore developer requests because they know what is best for everybody?

@chriszrc I don't see any hate in this thread, just a bunch of understandable frustration. I think equating this request and the related disappointment with "saving a few lines of code" is an exaggeration. It's not just this issue that is frustrating the community but the significant collection of popular issues that @fxck raised above that have been neglected.

Hi everyone, excuse us for the silence on this thread. There are two orthogonal requests we've been getting for a while:

  1. Better first-class RxJS support in the framework
  2. Less RxJS in Angular, potentially making it optional

Both requests are on our radar, and both have their pros and cons. For example, if we go the first direction, we'll make the framework less accessible to engineers new to the expressive, semantically rich API of RxJS. A lot of folks have concerns in using RxJS everywhere in their Angular apps, making the source code hard to read across team members with different experience levels.

At the same time, we already have a lot of reactive APIs, but some of the primitives offered by Angular are entirely imperative, and things don't wire up quite well. That said, it makes sense to improve the reactivity support, but should this be part of the core of Angular or delegated to a community project (ngrx - Angular's reactive extension, for instance) that we're collaborating closely with?

There are many ways we can solve this issue, but we need to consider:

  • Backward compatibility - not only for source code but also training resources
  • Learning curve
  • Consistency with current APIs
  • Consistency across projects
  • Performance - both runtime and initial load time

We're in the process of prioritizing some of the top GitHub issues, looking at the most requested and impactful improvements we can address. I'd say that this is one of the more challenging ones, so it's hard to commit to a date.

@mgechev Thanks for responding. If the rxjs and the reactive apis are going to get split out into another extension (not my personal vote), would it possibly make more sense to have that not coupled with a particular state-store/redux implementation? I quickly moved on from ngrx to ngxs (which felt like way less boilerplate, and way more "angular" with decorators) and then finally to Akita, which is my current favorite and the one I've been developing with the most. Or if it does get lumped in with ngrx, at least make really it easy to just add the parts we need, so we're not locked into using ngrx or including those dependencies-

If the rxjs and the reactive apis are going to get split out into another extension (not my personal vote)

I am not saying that's what is going to happen. In my comment I'm just sharing an incomplete list of alternatives so that I can show the scope of the project and different considerations we have.

@mgechev indeed, thanks for the reply.

I do wonder however, if the reactive part of Angular get's somehow "demoted" into the community project, wouldn't that mean reactive will become a second class citizen of Angular?

@mgechev I feel your pain being torn in two directions at once. Our team is actually not opposed to splitting the imperative / reactive pieces.

Here would be our requirements for such a split:

  • Using both imperative and reactive need to feel native and neither should feel bolted on
  • No tie in with specific state management solution to enable reactive (full disclosure we have migrated all 50+ projects to use akita by now)
  • Both options need to be released in a single version at the same time (no lag / delay)
  • There can be no "favorite", anything angular does would need to work in both worlds while feeling native
  • Full official support for both approaches backed by the angular team (Based on our experience this is a customer hard stop customer requirement)

Based on the above:

  • There are 2 main options:

    • core imperative + addon reactive

    • core reactive + addon imperative

  • Wrapping reactive to make it seem imperative is pretty straight forward, not so for the other way around
  • Hence we would vote for using reactive in the core and making the addon contain the imperative APIs
  • Due to the zero delay + no favorites requirement as well as required official support I do not see how the addon can be a community project

I understand the above is our view of the world and there are plenty of others. The reason I' writing this is:

  • If you land on extracting reactive into a community project we will have to migrate 50+ solutions to another framework (again this will be customer driven, not our choice)
  • So I would ask to let us (the community) know ASAP where you land on this so we have time to retrain our devs on another framework and migrate those projects

add the feature please

@mgechev I don't get your concerns. This proposal is about combining the two worlds with a uniform and straight forward to novice developers interface. It's not about choosing one or the other but rather enabling the combination. For example developer x decides to build an awesome reactive component. And developer y decides to use it in his not so reactive project. Why not? Why does he need to depend on any ngrx glue?
The difference between the two worlds is whether you store/ manage state in your ultimate smart component vs the central state store and that's what ngrx should be about, but for components I feel that the framework itself should be the enabler.

There are two orthogonal requests we've been getting for a while:

  1. Better first-class RxJS support in the framework
  2. Less RxJS in Angular, potentially making it optional

I'd be fine either way, but this sometimes this sometimes that gives a disjointed feel to Angular, which is the last thing you would except from a batteries-included framework.

Personally, I'm curious to see how you would even have non-RxJS versions for all the Angular packages (HTTP, Router, Forms). I suspect there aren't good non-RxJS versions of these, which is why they have RxJS in the first place.

That is to say....unless I'm missing something, (2) is not feasible.


P.S. I wouldn't describe those requests as "orthogonal"; more like "opposite."

Less RxJS in Angular, potentially making it optional

Out of curiosity @mgechev , are there any Github issues for that? (I haven't seen any.) Or is this more a Googler-thing?

@pauldraper I've seen at least one issue on github where someone is complaining about how horribly complex rxjs is and wanting it to be completely optional. Personally I love rxjs, but I've worked with two teams now where it brought fear and loathing to both junior and senior developers. Also, orthogonal is the better term than opposite, since it is possible to implement both requests at the same time (given each solution can be worked without one detracting from the other by providing multiple API options to consume things reactively and imperatively).

For every one comment complaining about rxjs on github there are probably thousands of devs using and enjoying it without a problem.

image

image

Here are the results from that form I posted above (almost 200 people responded), as I was discussing them on Angular discord.

Unsurprisingly forms are the biggest pain in the ass, but apparently @brandonroberts and @MikeRyanDev might be cooking something, at last.

For every one comment complaining about rxjs on github there are probably thousands of devs using and enjoying it without a problem.

Even though I love rxjs, I'm not this optimistic. I worked with a lot of devs who are so burned out the thought of having to commit time to learn something with a steep learning curve is a nightmare. And a lot who care far more about earning money than coding :D Or the aggressive junior devs who think that anything they can't learn in the space of a day must be trash.

I worked with a lot of devs who are so burned out the thought of having to commit time to learn something with a steep learning curve is a nightmare. And a lot who care far more about earning money than coding

Those are the devs Angular's trying to cater to then, burned out and without wanting to learn? :) And who even cares at this point of time anyway. Angular's been around for a while, it's not going anywhere and it's absolutely not gonna lose any traction if you add observable lifecycle, observable input, observable events. Just add those three small things and people will be happy for a while, that's it (and follow that with https://indepth.dev/component-features-with-angular-ivy/ to complete the basic package).

angular_rxjs

This one says it all. IMHO Angular should stay consistent and use more RxJS: with no RxJS at all it wouldn't be Angular.

Those are the devs Angular's trying to cater to then? :)

Yes, it would be pretentious to only cater to developers who want to write code using rxjs. Even though I prefer to use rxjs, I want Angular to cater to both sets of developers. Why should Angular cater to us only and not those who think differently? Especially when I believe that we are in the minority, not the majority.

Again, going "fully reactive", as in adding observable lifecycles, inputs, events wouldn't in any way affect those you are talking about, but would make the other group very happy.

And components features are useful whether you like reactive programming or not.

@fxck I never disagreed with that for a second. I was just responding to your earlier comment to point out that there are many people who don't want to use rxjs and many of those have opened github issues to complain about it.

Despite how angular decides to develop the core - reactively or not, in the ideal world there would be the opposite package built on top to cater the opposite needs (e.g. @angular/reactive or @angular/imperative - with better names hopefully).

Either of these two going to community is for me a downgrade for some people and for me angular having an outlook of being a great reactive framework was a reason to go with it in the first place.


On a side note, I think it would be easier keeping angular reactive and having imperative extensions, as this is way easier to bridge, rather than bridging imperative to reactive - speaking for the simplicity of both the core and the extension package.

Disclaimer: the last point I formulized based on assumptions - wouldn't be surprised if it's much easier to write the core imperative - extension reactive would be more complex tho.

Out of curiosity @mgechev , are there any Github issues for that? (I haven't seen any.) Or is this more a Googler-thing?

Not an internal Google thing. You'd be surprised (just like I was, when I joined the team), how large is the intersection between external and internal requirements. The main difference is in the build system and dependency management, aside from that Googlers have pretty much the same requirements as non-Googlers.

We're in touch with thousands of developers - a lot of external companies, internal teams, and individual contributors. In both cases there are folks who'd love to go full-in with RxJS and others who don't think it's the right choice for them. Both camps have excellent arguments.

This is not a decision we'd want to rush, especially given that there are well established workarounds/community solutions The work done in community helps us collect extra data points and establish an optimal solution for the current set of variables.

I think having one unified approach reactive or imperative (it being a choice per project) when developing an angular app would be highly beneficial. The ability to mix and match does not aid the development experience and create non DRY code (eg. non reactive inputs).

Nothing happens in isolation, so I can totally understand corporate environments having a hard time to re-train large amounts of devs to reactive programming. So dropping imperative really would move angular out of the corporate sweet-spot, which lets be realistic is just not going to happen as it makes up a large key userbase for a framework like angular.

That said what I do not see as being realistic is building a reactive interface on top of an imperative one. The other direction is pretty much straight forward as you can always write the output of an observable into a variable that then can be used imperatively. In fact that's what angular is already doing in many places under the cover.

Hence I vote for making angular fully reactive at its core and then create imperative "wrappers" on top.

The main issue with this approach would be very likely larger migration steps for imperative users. Which is a nono in corporate environments which might be exactly what the angular team is trying to prevent, hence the suggestion todo imperative at the core.

@mgechev Since this has been raised a couple of times it would be interesting to hear your thoughts about reactive core / imperative extension and if it has any leg to stand on?

In both cases there are folks who'd love to go full-in with RxJS and others who don't think it's the right choice for them. Both camps have excellent arguments.

Great, good to know. Define going full-in with RxJS? How does adding observable lifecycle, observable input and observable events fit into that? And no, none of these really have a "well established workarounds/community solution".

@fxck none of these really have a "well established workarounds/community solution".

It's true. I wrote one of these solutions and it only works due to one big hack that relies on poor type-checking in templates. I've checked out a few of the other solutions posted in this thread too and each of them has at least one of the following problems:

  • subscription leaks
  • boilerplate requirements on the user
  • hacks as bad, if not worse, than the one I used in my library.

As far as I'm concerned, it's impossible to do this nicely.

Observable events are even worse, there are not that many community solutions at all, they usually require additional build step (which in some cases breaks SSR in monorepo setups) and hacks on top of that even (if you are using class extension for example to get lifecycle observable events, because hey, angular doesn't support that natively) https://github.com/typebytes/ngx-template-streams/issues/8

Lifecycle events are arguably the "easiest", but still have to rely on a class extension or custom decorators, none of which is ideal.

@fxck As far as I'm aware it's not possible to clean up lifecycle event subscriptions without having to use a parent class (eugh) or a method the user has to call from their own destroy lifecycle event (even worse).

Lifecycle events are arguably the "easiest", but still have to rely on a class extension or custom decorators, none of which is ideal.

I had tried to implement lifecycle events (to get it reactive) with custom decorators too and it's a pain. ~Without class extension I don't know if it's possible without 100 hacks~. The user-possibility to extend angular is so far very poor and it relies on hacks or a lot of boilerplate to do it.

@tonivj5 If component feature's would be a public api do you see this as a potential way to implement lifecycles without inheritance?

@ntziolis hah funny you should mention features, I'm actually working on the lifecycle part of ngx-sub-form and features is exactly something that I think would help. In the meantime it is very doable to patch the component factory with ivy. I see this as being very useful outside of ngx-sub-form, so I think I will split this logic out into a separate lib

@ntziolis at this point I'm unsure if we will ever see the Ivy promises actually being delivered.

Have you checked angular effect? (not ngrx/effects) https://dev.to/stupidawesome/reactive-adventures-in-angular-introducing-angular-effects-1epf With this tool you can write fully reactive applications.
Two-way observable state between parent and children components included
https://dev.to/stupidawesome/exploring-the-angular-effects-api-2gol
Version 9.1.0 will introduce a composition/hooks model based on Vue 3’s Composition API.
I think it's a really next step for angular to work with reactivity.

@mgechev

This is not a decision we'd want to rush, especially given that there are well established workarounds/community solutions

Just curious, who is we and how many Googlers actively contribute to the Angular decision making process?

You indicate this is not a decision that should be rushed, but I wondering what is your definition of not rushed? Is this one of those slap a 'Fixed by Ivy' tag on it and ignore it until more developers start making noise again type situations? Is there a targeted version in mind for any reactive work or are there other newer compiler versions have to be released first?

Does the fact that there are usually 2500 open issues at any given time ever come up in internal discussions?

@ntziolis, as @zakhenry said, I think features would help

@ntziolis I have given other try with the lifecycle and I have a working POC (without class extension nor implements lifecycle interfaces). It relies on private API (:exclamation:)

@tonivj5 hah I haven’t had a chance to read yours but Ive nearly got my solution released too :) https://github.com/cloudnc/ngx-observable-lifecycle

The idea with the lib I'm working on is to have a common base for which other libs can hook in to for creating their own life-cycle aware functionality. It should be able to work such that if there are multiple functions wanting access to the same hook, there is only the one hook decorated onto the component def.

I've got it all working, just need to sort CI and unit tests.

Does the fact that there are usually 2500 open issues at any given time ever come up in internal discussions?

Lol, there haven't been 2500 open issues since mid-2019.

$ github_issue_stats history -i2m -n20 -sangular/angular

+-------------------------+--------------------+
|         period          |       issues       |
+-------------------------+--------------------+
| This month (2020-05)    | 2855 (+137, -112)  |
| Last month (2020-03)    | 2830 (+495, -550)  |
| 2 months ago (2020-01)  | 2885 (+601, -575)  |
| 3 months ago (2019-11)  | 2859 (+437, -352)  |
| 4 months ago (2019-09)  | 2774 (+411, -305)  |
| 5 months ago (2019-07)  | 2668 (+441, -369)  |
| 6 months ago (2019-05)  | 2596 (+488, -349)  |
| 7 months ago (2019-03)  | 2457 (+425, -373)  |
| 8 months ago (2019-01)  | 2405 (+428, -330)  |
| 9 months ago (2018-11)  | 2307 (+425, -391)  |
| 10 months ago (2018-09) | 2273 (+515, -466)  |
| 11 months ago (2018-07) | 2224 (+641, -541)  |
| 12 months ago (2018-05) | 2124 (+690, -624)  |
| 13 months ago (2018-03) | 2058 (+605, -444)  |
| 14 months ago (2018-01) | 1897 (+773, -679)  |
| 15 months ago (2017-11) | 1803 (+815, -979)  |
| 16 months ago (2017-09) | 1967 (+671, -431)  |
| 17 months ago (2017-07) | 1727 (+664, -518)  |
| 18 months ago (2017-05) | 1581 (+854, -548)  |
| 19 months ago (2017-03) | 1275 (+987, -796)  |
| 20 months ago (2017-01) | 1084 (+671, -505)  |
+-------------------------+--------------------+

To my taste I prefer open source projects that keep issues open to discussion until there is clear community discussion/consensus rather than projects that close each issue opened without discussion. It's also a step for maintainers to explain their concerns over time to the community before they shut any possibility for accepting a proposal.

@agalazis This issue has been open for 4 1/2 years and pretty much ignored for the last 3.

@agalazis This issue has been open for 4 1/2 years and pretty much ignored for the last 3.

There was an Angular team member explaining why this is still open just 5 days ago so you're simply not right.

@etay2000 Some decisions are tough some times since they affect the evolution of the whole project and that's acceptable Developers can realize that they cannot rely on the feature in the near future as the time passes, but if there is a possibility why kill it prematurely? I do believe that the easiest thing was to reject the proposal and close the issue but it didn't happen for a reason.

@beeman

There was an Angular team member explaining why this is still open just 5 days ago so you're simply not right.

You really like those thumbs down emojis huh? Was that really an explanation though? After 4+ years he said they don't want to rush the decision.

@agalazis
I agree some decisions are tough, but what should be considered an acceptable time frame to put off making those tough decisions? Not all of the 2855 open issues involve these tough decisions, yet a lot of those have also been around for quite some time also.

@etay2000 Accept it or not this is open source people who open issues are much more than the maintainers. Typescript project for example has nearly twice as many issues open and another proposal I did there took a long while as well. I don't mind since the discussion there brought many alternatives that are not as fancy as having the feature but managed to see a lot of other perspectives

@agalazis You are right, I guess I (incorrectly) expected more from a open source project maintained by Google than I would from a smaller project.

@beeman Insert thumbs down emoji here: -------->

@etay2000 You should always remember that each such important decision affects hundreds of thousands of things, projects, and people. And what is even more important, a not perfect decision and introducing public APIs, that would lead to some breaking changes in a short time after that, is just a nightmare. You can see almost on each PR, how each step is reviewed, and if not perfect, it simply waits, weeks, months or even years.

@agalazis You are right, I guess I (incorrectly) expected more from a open source project maintained by Google than I would from a smaller project.

I don't know, look at Go and dart also. Google are actually pretty famous for ignoring hugely popular community requests for half a decade :D In general their approach to languages/frameworks/etc. is very conservative. You can see new languages and ideas popping up that revolutionise areas and google still not adopting them for years, e.g. null safety hit Kotlin, TypeScript and Scala a long time before Dart. I guess there are benefits and deficits to this kind of approach, but for me at least I tend to avoid Google developed things where possible because it doesn't really fit with my ethos.

(Sorry for this, everyone, but I have to do it.)

@beeman Insert thumbs down emoji here: -------->

@etay2000 I don't know how this kind of comment help at all, if not a violation of conduct here. I'm pretty sure everyone knows how to put thumbs down, so what's the point of the sarcasm?

Just as a reminder, no one is forced to use Angular, you can try to find another framework where people please you more.

@brunojcm I guess the party is over now that the comment police are here. The point was he thumbed down all my other comments, but I didn't realize sarcasm was a violation of conduct.

Just as a reminder, no one is forced to use Angular, you can try to find another framework where people please you more.

The way I really want to respond to that would definitely violate the code of conduct on here.

I'm done, everyone can return to their regularly scheduled programming. I'll check back in another 4-5 years to see how things turned out.

@tonivj5 @zakhenry Great to hear that this might be an avenue.

@mgechev I understand this is not even a preliminary discussion, but would love to hear your thoughts on :

  • reactive core + non reactive extension vs the other way around.
  • and more specific to this issue is there any realistic chance of exposing the feature api in any way.

    • even if its just with the caveat of breaking changes in the future as long as the general func would still be accessible.

    • As @zakhenry has done for lifecycle events I see a one or very limited number of projects building APIs on top that can be used by others instead of directly accessing these apis

    • You could then work with these wrapper team/s to let them know about upcoming breaking changes early on (so very similar like your suggestion on reactive extensions)

I think you guys can directly apply Vue 3.0's reactive module (ref or reactive) and resolve this issue.

@AnonymousArthur if you are talking about package @vue/reactivity then it's is completely unrelated to what we are discussing here as it is providing reactivity to properties and has nothing to do with reative streams (which is what RxJs is).

@gund Yes, I agree. However this conversation takes quite a long time (4.5 years) and not finished yet, so I just pop up an idea (might not be) very quickly for whom don't want to write subscribe/unsubscribe or ngOnChange Handler. RxJS does provide reactivity feature and this conversation(didn't read all of it) is talking about wrapping the Input value with the Observable as an syntactic sugar to make it watchable and I think it is an awesome idea.

I think this idea is really useful and @robwormald's prototype towards the beginning looks great, but I think it has undersold the potential benefits and how little the impact would need to be.

Let me propose a slight tweak on that solution to fix a few shortcomings, but basically the same approach:

Angular would define a decorator @OInput() and a type EventReceiver<T> that extends Observable<T> but also adds a .value getter (like BehaviorSubject<T>).

On the parent component side, as in @robwormald's example, nothing changes. If you want to pass an Observable value there, you still need | async. Or you can pass it a non-observable type, that's fine (as always), too.

On the child component side, here's what I propose it looks like (a slight deviation from that proposal):

@Component({ selector: "child" })
class Child {
  // Notice, this parallels the patterns of `@Output()`.
  @OInput() foo = new EventReceiver<MyType>();

  constructor() {
    // The reactive way to listen to input changes in the class.
    this.foo.subscribe((v) => {
      console.log('foo changed', v);
    });
    // Or you can bind to `foo | async` in the template.
  }

  // But this would also support less reactive patterns in parallel,
  // both for ease of migration and for cases where developers don't
  // want to migrate fully. 
  ngOnChanges(changes: SimpleChanges) {
    if (changes['foo']) {
      console.log('foo changed', changes['foo'].currentValue); // Unchanged
      console.log('foo changed', this.foo.value);  // Previously this would have been just `this.foo`
    }
  }
}

Now here are the benefits of this approach, which I feel like were a bit undersold:

  • This enables effectively fully reactive designs in both the parent and child components, if desired.
  • In parent components, maintains Angular's existing input design patterns, so that no component is forced into this or has to design around it.
  • The parent and child context are entirely independent, the parent doesn't need to know if the child is using Input or OInput, eliminating the risk of cross-component bugs from this change.
  • It's relatively easy to partially migrate a single child component, if desired, because Angular keeps these all connected to the existing lifecycle events as before.
  • Since Angular implements this feature, all EventReceivers can internally include a pipe through takeUntil(ngOnDestroyEvent), so most cases won't need to remember to unsubscribe when their component is destroyed, because these observables will automatically complete. (Yay reduced memory leaks!)
  • In this child component, this looks and functions very similar to the pattern of @Output() today, so gives some nice parallelism and potential ability to connect them nicely.

    • Side note: as a follow-up, I think it would be cool to propose an @InputOutput() that uses a ReplaySubject<T>(1) to connect the behaviors for a two-way binding more seamlessly and consistently. But that has its own challenges and arguments, so I am NOT proposing that here.

  • No new types of boilerplate to make this work, this is as simple as @Output().
  • Angular would seamlessly switch() over changes to the Observable being input by the parent, so weaker reactive patterns like that not sticking with the same Observable instance don't need to be special-cased (switch()ed) in child components.

Side note about the name OInput that I picked: Obviously that is open to debate. However, I personally like that name because it is short for "Observable Input" AND because it looks kind of like "Output" which is what this mirrors.

Dear Angular team. Please give us something to look forward to in 2020 :-)

Also @jcomputer solution is exactly what I would be wanting. Not a huge fan of a different decorator name, but maybe it is feasible to add a parameter similar to how @ViewChild has { read }. eg:

@Input({ observable: true }) 
@Input({ asObservable: true }) 
@Input({ asSubject: true })

So much for having something to look forward to in 2020. :D Unless of course this (and other issues listed above) count as a bug and not a new feature. :)

https://twitter.com/ThomasBurleson/status/1283902827467886592
image

@fxck I may have an unpopular opinion here but honnestly if 2020 is the year were Angular team decides to squash a lot of bugs on forms, router etc I wouldn't be mad at all with 0 features :shrug:.

image

That said, maybe it's more an issue related to the recent events and I assume there are complicated things going on at the moment in the Angular team. I hope they manage to keep the great people who've been actively building Angular so far :heart:. But that's another story.

Sorry for the off topic. Flies away

@maxime1992 It would be fine also for me.

I may have an unpopular opinion here but honnestly if 2020 is the year were Angular team decides to squash a lot of bugs on forms, router etc I wouldn't be mad at all with 0 features

But what makes me nervous is the fact that there are long term un-healthy HR processes inside the Angular team that affects us, without us. Especially from the point of view of massive investment into this area.

From my POV, they are fixing issues mainly by closing them via BOT - leaving without response and closing by bot.,.. :-/

@montella1507 No, this is not exactly true. The bot locks only already closed issues. And it's already true that the Angular team members have plenty of effort in many cases when they try to explain what is necessary to describe and reproduce when new issues are entered. It's a very time-consuming process and requires a lot of patience.

For those, who are blaming the Angular team and complaining about not getting features and changes quickly:
I do understand your pain. I'd also love to see this feature in Angular, I'd also change a lot of stuff I personally don't like.

But maybe Angular is not meant to be a framework that has all the shiny new toys and get tons of features each release. And that's fine with me. There have to be frameworks that aim for more enterprise-level and provide stability and reliability. And Angular does that just fine, at least from my experience.

I like Vue more. I use it for my personal projects. But my projects can quickly start to feel outdated and I feel the urge to upgrade to a new component style. Also, when I do upgrades, things always break in the weirdest way. The ecosystem also seems to have a harder time maintaining compatibility.

Angular in contrast is mature and stable. It doesn't change often, but that also means you have less work in refactoring your code as you keep your dependencies updated, and that is valuable for commercial products. Your knowledge also stays relevant for longer, and instead of trying to keep up, you can go in-depth.

@manfreed people aren't asking for a shiny new toy though, they're asking for a correction to an oversight in the design of the framework. Currently we're sometimes forced to use observables, and sometimes unable to use observables, for key functionality. Those who hate observables are frustrated. Those who love observables are frustrated. And many many of us were so disappointed by the situation we gave up and moved on to other frameworks. I would have loved to continue using Angular, a bit of direction and it could have been a truly great framework. But blog posts about mismanagement, the lacking of pragmatism, the oversights, they're all objectively disappointing.

@insidewhy Be patient, there are always some peaks and valleys on the road, but it doesn't mean that others don't have them also or that there are some principal mistakes. It only means that things could move forward faster and effectively than they actually did.

There was no mention of any particular aforementioned issue in the roadmap, which I found saddening, I was really hoping there would be something, mention, acknowledgement... this discussion followed on Angular discord —

image

I gave them a benefit of the doubt and asked in the comment of that medium roadmap article, Minko's response:

image

He pretty much reiterated what he said here few months ago, none of these rxjs related issues is getting fixed anytime soon, so yeah.

I'm done trying to get my point across, but let me try one last time.. I'm not asking for Angular to be turned into Cycle.js, replacing current APIs, all I'm asking for are three little reactive cherries on top of the current APIs.

  • observable lifecycle
  • observable input
  • observable template events

None of these break backward compatibility, increase learning curve, is not consistent with other APIs and I can imagine hardly affects performance, so just how are they so tricky and require longer & careful planning, compared to other tasks laying ahead anyway. Just add one at the time, show that you care. Please.

@fxck :+1: for sure.

  • observable lifecycle
  • observable input
  • observable template events

@insidewhy Be patient

Asking people for more than 5 years of patience is not so pragmatic when there are plenty of competitors running past in the race all vying for attention.

@insidewhy It was meant more generally.

@fxck Google has (by my last count) 4000 apps built in angular and highly similar in nature, switching between these projects and peer reviewing is (I imagine) pretty seamless. Even at my company, one of the huge benefits of Angular is that without me even reviewing another team's code, I know it's in a state where a peer review doesn't fire off an entire investigation.

Now lets say we implement each one of these helpful RxJS shortcuts into the core, what happens then? It's possible we'll end up with a procedural bias versus a reactive bias, without clear guidance of which bias is correct for any particular case. After reading through the discussions so far, the answer from the angular team isn't "This is a low priority" (as your flow suggests), it actually seems closer to "We don't want to take sides".

The advanced RxJS users in the Angular community here are a vocal minority, because after you grok Typescript, DI, templating, and Angular's various libraries, you've got almost 1 year under your belt using the framework daily, and you're now ready to completely understand RxJS. Letting senior level people go off with reactivity biases in peer reviews alienates people even more, and that's literally the last thing Angular needs.

Angular's goal (as I see it) is to reduce and tune down conversations away from "Use X tech because it's better, heres a short novella why" and keep conversations in peer reviews about the business logic being implemented. Do we really want to stratify our components between "Advanced" angular and "Beginner" angular any more than we already have?

This is arguably the same arguments we've seen with state management, why should Angular determine from the many possible patterns which one is correct?

Let me just quote one of the angular team members for you.

image

There is, by the way, absolutely nothing advanced about any of these (observable lifecycle, observable input, observable template events).

This is arguably the same arguments we've seen with state management, why should Angular determine from the many possible patterns which one is correct?

The difference between state management and this, is that state management could be done by community, there is nothing inside angular core preventing it. Unfortunately Angular doesn't provide ways to properly implement neither of those three I mentioned. (edit: corrected link to comment)

I'm wholeheartedly for leaving as much to community as possible, that includes packages like forms, router, flex-layout, universal etc., let Angular team focus on core, cli and components. But for that they need to provide community with enough entry points, like for example allowing higher order components. But they failed to do that for years (oftentimes saying Ivy is needed first) and refuse to acknowledge / talk about this in their plans now.

After reading through the discussions so far, the answer from the angular team isn't "This is a low priority" (as your flow suggests), it actually seems closer to "We don't want to take sides".

Yes and it is scary.

@fxck I very much think we're on the same page about this. I would say that every time I bring up RxJS in forums or even with my fellow engineers, most of the quotes I can cite are "I still don't understand this, how do I learn more?" or "I find it overwhelming how many operators there are." or "I'm having trouble reading this pipeline in this PR". For every 1 well versed RxJS engineer, there seems to be 15 well versed Angular engineers with furrowed brows.

Yes and it is scary.

This is little hyperbolic, we don't "need" @angular/core to have these patterns, in fact there are many MANY variants and libraries within this issue that can be used today on any project. The only reticence in using the previously mentioned options is that you may possibly, in the future, have to migrate to something Angular provides as a standard @angular/core replacement. Is it really that hard for us to npm uninstall and fix all the typescript errors?

Major architectural decisions, that affect all angular projects, and require innumerable hours to document and migrate if they don't work, to me that seems even more frightening, and we've been there before:

This is little hyperbolic, we don't "need" @angular/core to have these patterns, in fact there are many MANY variants and libraries within this issue that can be used today on any project.

No, not really, each solution require hacks or rely on internal APIs that could change. That's the whole point.. read what @insidewhy said https://github.com/angular/angular/issues/5689#issuecomment-630661006 and what I said below that about template event streams.

// edit corrected link to comment

No, not really, each solution require hacks or rely on internal APIs that could change.

What internal APIs or types do you think should be made public/generic to allow this to be addressed by the community? If this design is in a holding pattern because there isn't a clear path forward, then it seems appropriate to ask that we are allowed to design our own rather than constantly banging this same drum.

Read the other comment by @insidewhy he tried to get it done inside core.

image

@fxck I'm not going to discuss the history of attempts to implement this in core or how this issue has been open for 5 years, what is stopping us now from opening up the internals to allow the community to develop a design themselves?

Yo @insidewhy, I wonder if this is the type checking hack your lib relied on. Apparently it doesn't work anymore using TS 4.0

Property 'serviceStackId$' is used before its initialization.ts(2729)

image

Yo @insidewhy, I wonder if this is the type checking hack your lib relied on. Apparently it doesn't work anymore using TS 4.0

No, it was in the template compiler. This is something else. Damn. Ah well. I can add you to the maintainer list if you wanna try fixing it.

@fxck Actually you should assign that piped operator in ngOnInit since the decorator based properties won't be injected until after the constructor is run, so this is actually a legitimate problem with your code.

@insidewhy I definitely did work prior to TS4. And check this,

function ObservableInput() {
  return (target: any, propertyKey: any) => {
    Object.defineProperty(target, propertyKey, {
      set(value: any) {
        console.log(target, propertyKey, value);
      },
      get() {
        return 'ObservableInput modified value';
      },
    })
  }
}

class Foo {
    @ObservableInput()
    bar = 'original bar value';

    baz = this.bar;

    constructor() {
        console.log('loggging this.baz', this.baz);
    }
}

new Foo();

it logs

loggging this.baz ObservableInput modified value

so I think it should still work, only in TS4 the compiler complains because it doesn't realise there's a get with a value inside that decorator..

I'm using a decorator to sense the Input prop change and making an observable version of the Input prop. See this codesandbox demo.

This is how it works:

// subjectize.ts
export function Subjectize(keyToWatch: string): PropertyDecorator {
  return (proto: any, propKey: string) => {
    const internalKey = Symbol(keyToWatch);
    Object.defineProperties(proto, {
      [keyToWatch]: {
        get() {
          return this[internalKey];
        },
        set(value) {
          this[internalKey] = value;
          this[propKey].next(value);
        }
      }
    });
  };
}
// counter.component.ts
import { Component, Input } from "@angular/core";
import { ReplaySubject } from "rxjs";
import { Subjectize } from "./subjectize";

@Component({
  selector: "app-counter",
  templateUrl: "./counter.component.html",
  styleUrls: []
})
export class CounterComponent {
  @Input()
  count: number;

  @Subjectize("count")
  count$ = new ReplaySubject(1);
}

As @wmaurer pointed out, @Subjectize could be treated as a "sugar" to get things done.

It worth reading angular's official guide Intercept input property changes with a setter, which explains we can sense the Input changes using getter/setter.

@hankchiutw That solution looks similar to my @BindObservable decorator: https://github.com/PSanetra/bind-observable#usage

Thanks @hankchiutw

Since you're initializing ReplaySubject with 1 I chose to use BehaviorSubject instead.
Also I've initialized the value directly in Subjectize.

export function Subjectize<T>(keyToWatch: string): PropertyDecorator {
  return (target: Object, propKey: string) => {
    const internalKey = Symbol(keyToWatch);
    Object.defineProperties(target, {
      [keyToWatch]: {
        get(): T {
          return this[internalKey];
        },
        set(value: T) {
          this[internalKey] = value;

          if (this[propKey]) {
            this[propKey].next(value);
          } else {
            this[propKey] = new BehaviorSubject(value);
          }
        }
      }
    });
  };
}

@Component({
    changeDetection: ChangeDetectionStrategy.OnPush,
    selector: 'rol-bla',
    templateUrl: 'bla.html',
    styleUrls: [ 'bla.scss' ]
})
export class BlaComponent implements OnInit {
    @Input() world: World;
    @Subjectize<World>('world') world$: BehaviorSubject<World>;

    // ...
}

I wish I could avoid writing the type on the "Subjectized" property since it should be able to guess it from the related property :( Any idea how to do that ?

The dream would be to be able to do that and automatically create the related Subject prop (world$ in my case) as BehaviorSubject and properly initialized.

export class BlaComponent implements OnInit {
    @Input() @Subjectize() world: World;

    // ...
}

@mparpaillon Your proposed design is pretty much how it is done in https://github.com/PSanetra/bind-observable
The only difference is that the @BindObservable() decorator uses a ReplaySubject under the hood. So if you want that Subject to contain an initial value, you also need to initialize the bound property explicitly (also if it is just undefined as it could be possible that the property type does not allow undefined or null values).

Stackblitz Example

@Component({
  selector: 'app-my-component',
  templateUrl: './my-component.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponentComponent {
  @Input()
  @BindObservable()
  counter: number;
  counter$: ReplaySubject<number>;
}

Thanks @PSanetra but I prefer my solution (which is actually Hank solution)

@mparpaillon I've tried something for your dream(ha) in another demo.

The usage looks like

export class CounterComponent {
  @Input()
  @Subjectize()
  count: number;

  @Input()
  @Subjectize("myCount$")
  anotherCount: number;
}

where you can choose to specify the subjectized prop name.

Although it's technically feasible, I'm afraid that may be ambiguous for developers(since a new class member is created underhood).

Thanks @hankchiutw ! Typescript doesn't seem to let me use count$ or myCount$ though.

Capture d’écran 2020-11-12 à 10 11 50

Also you may be right about ambiguity... Thanks again

Typescript doesn't seem to let me use count$ or myCount$ though.

You declared your class members as "count" and "anotherCount", that's why you can't access "myCount$" and "count$". They simply don't exist, because you didn't declare them anywhere.

I know... that's the point. I was looking for a way to declare them from the Decorator. @hankchiutw offered a solution and I'm just saying it's not working as is

@mparpaillon take a look at my solution: https://github.com/Futhark/ngx-observable-input

@Futhark Oh that's hot ! thx

Was this page helpful?
0 / 5 - 0 ratings