Proposal: Support declarative binding from View events to Observables
See original GitHub issueNot 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 https://github.com/angular/angular/issues/4062#issuecomment-231615401 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 https://github.com/angular/angular/pull/3992, but I believe this is for emitting events “out” from the component, whereas this idea is more for usage within a component.
Thoughts?
Issue Analytics
- State:
- Created 8 years ago
- Reactions:43
- Comments:62 (35 by maintainers)
Just a little update. We think this use case is important and it should be included in the core of Angular. For now the focus is on Final, and this is a feature which can be added after final release, so don’t expect much progress until after final release.
update: the plunker angular version needs to be updated to latest angular for it to work again
I want access to child outputs in the constructor so can have full access to rxjs that way we can unlock the reactive potential out of Angular 2. Here’s an example using the initial plunker prototype
All I want is for everything in constructor to be Observables so we can wire everything up. This includes Input/ViewChild/ViewChildren/ContentChild/ContentChildren (pending router Data/Resolved/Params) which would allow for Angular 2 to become powerful with advanced reactive configs. If anyone wants to deal with sync values they can use the correct lifecycle hooks
@ObserveInput
@ObserveViewChild
@ObserveViewChildren
@ObserveContentChild
@ObserveContentChildren
/I got all of these working in a prototype via AngularClass/angular2-observe-decorators