Repository navigation
Proposal: Support declarative binding from View events to Observables #4062
Description
Not sure this is a good idea, or even possible, but thought I'd throw it out there.
In vanilla Rx, if I wanted to listen to a DOM event to do a typeahead or something I'd do something like:
//get DOM element
const input = document.getElementById('myInput');
//observable of click events
const inputs$ = Rx.Observable.fromEvent(input, 'keyup');
//map changes to requests
const responses$ = inputs$.flatMap(ev => myHttpService.get(ev.target.value));
//subscribe to responses
responses$.subscribe(json => console.log(json));In current ng2, if I wanted to do the equivalent, I'd do something like:
@Component({
selector: 'my-component'
})
@View({
template: `
<div [ng-form-model]="myForm">
<input type="text" ng-control="query">
</div>
<ul>
<li *ng-for="#result of results | async">{{result.text}}</li>
</ul>
`
})
class MyComponent {
constructor(public http: Http, fb: FormBuilder){
//create form group
this.myForm = fb.group({
query: ""
});
//subscribe to value changes, map to responses, bind to view w/ pipe
this.results = this.myForm.controls.query.valueChanges
.toRx()
.flatMap(query => this.http.get(`/foos?q=${query}`)
.map(res => res.json());
}
}This all works great (or will, once Rx stuff settles).
However, if I wanted to do the same sort of thing from an arbitrary event (unrelated to forms, like a mousedrag or button click or whatever), there's not a good way (I can see) to get an Observable from a DOM event, so you have to do something like:
<button (click)="makeRequest($event)">Make Request</button>//snip
class MyComponent {
makeRequest($event){
this.http.get($event.target.url)
.map(res => res.json())
.subscribe(results => this.results = results);
}
}which isn't nearly as clean.
Proposed idea would be to provide a way to delegate / bind an arbitrary DOM event to a Subject/Observable, so that it could be easily subscribed to and handled reactively.
Something like (totally made up syntax here, point being we're binding the click event to the Subject):
Edit: see #4062 (comment) for current proposal
<button [(click)]="clicks$">make request</button>class MyComponent {
clicks$ = new Rx.Subject();
constructor(){
this.results = this.clicks$
.flatMap(ev => http.get('someurl.json'))
.map(res => res.json())
}
}I saw #3992, but I believe this is for emitting events "out" from the component, whereas this idea is more for usage within a component.
Thoughts?
Activity
PatrickJS commentedon Sep 9, 2015
👍 it would be awesome to have Rx Subjects for two-way data-binding
dsebastien commentedon Sep 9, 2015
+1, let's RX all the things :)
jeffbcross commentedon Oct 29, 2015
I was chatting with @vsavkin earlier today about this, but more from the perspective of putting the component in control instead of the template. He had the idea of extending the
@ViewChildproperty decorator to something like@ObserveChildOrBetterName('.some-button', 'click'),This could work for native and custom events, and, aside from setting the
MouseEventas the generic type, has no tight coupling to the DOM, so this component is more portable to different platforms.ericmartinezr commentedon Oct 30, 2015
@jeffbcross that would be beautiful 👍. Although I would call it
@ObserveOutput()to keep it aligned with the latest naming.flyingmutant commentedon Nov 16, 2015
It would be nice to also use the hypothetical
@ObserveChild()to translate this:into
Having to use
[ng-form-control]to observe the values does not feel very natural currently, and clutters the template as well.flyingmutant commentedon Nov 16, 2015
Aside: isn't it amusing how the things move from onclick-style (attach things right in the DOM), to jquery-style (attach things after the fact using selectors), to angular1-style (= onclick-style reborn), to angular2-style (
@ViewChild,@ObserveChildetc. – jquery-style reborn)?#CleanTemplates2015
0x-r4bbit commentedon Nov 29, 2015
Love @jeffbcross and @vsavkin proposal. Thanks @robwormald for bringing this up.
@ericmartinezr as a site note, I think
@ObserveOutputdoesn't really fit here, as "outputs" describe what goes out of the component. This pattern however, describes how to listen/subscribe to something inside the component as part of the component's view. So it's not really an output.But i'm sure we're going to find a nice name here, as naming is sooo easy.
danculley commentedon Dec 22, 2015
Not to add to the naming soup, but I think
@ObserveChildEvent()and@ObserveHostEvent()would make the most sense.@ObserveChild()is not sufficiently generic, as the same concept makes sense for observing DOM events on the host element as well. The semantics also do not match exactly, because the bound variable is observing an event on the child, not the child itself.@ObserveOutput()is (as @PascalPrecht describes above) confusing because it is not just an observable version of@Output().@ObserveEvent()identifies the event, but not where it is coming from.thelgevold commentedon Dec 31, 2015
I have been playing with Observables tied to a UI element and some event.
One issue I've had is passing data via the event - without storing and passing state from the DOM.
I have been using
fromEvent, but I end up having to pull info from the DOM element to make it work. The use case is to pass an id to build a dynamic url when an element is clicked.I would love to be able to just pass arbitrary model data to processes triggered by the event. I would also like to abstract the underlying element and perhaps group it with other elements with the same behavior, but with different data.
One idea I came up with was a concept of an Observable group
I am new to Observables, so I am not sure this is the right direction, but it does seem to meet some of my goals
edispring commentedon Jan 18, 2016
👍 for @ng.ObserveChild()
valorkin commentedon Jan 19, 2016
Observe all the things! 👍
mhevery commentedon Jan 27, 2016
I think this is a good idea, post RC.
46 remaining items
mgechev commentedon Jul 14, 2016
I like the proposal. The declarative bindings will not only enforce a better style of reactive programming but also stimulate applications with logic-less templates, which will increase cross-platform portability.
On top of that, having access to the
Subjects in the controllers' constructors will help us write even more declarative code (as the prototype of @gdi2290 shows).fxck commentedon Oct 6, 2016
Is this being worked on now that final is out?
PatrickJS commentedon Oct 10, 2016
I have a lib published if someone wants to experiment with the decorators
fxck commentedon Oct 10, 2016
Sure, where can I find it?
otodockal commentedon Oct 10, 2016
@fxck https://github.com/AngularClass/angular2-observe-decorators
amcdnl commentedon Nov 8, 2016
@robwormald @IgorMinar - Is there any status updates on this?
I spoke w/ @gdi2290 the other day and we think I've got a pretty good use case for the issue being discussed.
In angular2-data-table I have the ability for users to re-order table header columns using 2 controls:
orderableanddraggable. In this scenario,draggableis completely decoupled fromorderable. The header container is theorderableand the column cells aredraggables. Code.The
orderableusesViewChildrento subscribe to 2 events on each of thedraggableslike:unfortunately since the column headers that are draggables can change, I have to use
Differsto constantly diff the columns, unsubscribe from old one and subscribe to new ones like so:using @gdi2290 approach this could be very clean.
PatrickJS commentedon Dec 17, 2016
see current issue for better rxjs support

#13248
amcdnl commentedon Dec 19, 2016
@gdi2290 - should this be closed now?
mhevery commentedon Dec 20, 2016
Closed in favor of #13248
angular-automatic-lock-bot commentedon Sep 13, 2019
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.