I have a slider component that emits numbers while you drag the slider, which is usable like so: <my-slider (change)="onSlide($event)"></my-slider>
. I'd like to get rid of the onSlide
method and instead bind the change
event stream to an Observable<number>
property (instead of a callback).
I am using an Angular 2 EventEmitter
for my @Output
. EventEmitter
inherits from a RxJs Subject
, which is an Observable
and an Observer
. I wish to reuse the Observable
side of the EventEmitter
.
Of course I can push values that enter through onSlide
onto another Subject
, but I wish to prevent this boilerplate and overhead. Is there a way?
EventEmitter is used in the directives and components to emit custom events either synchronously or asynchronously. Since EventEmitter class extends RxJS subject class, this means it is observable and can be multicasted to many observers.
The @Output() 's type. Tells Angular to create a new event emitter and that the data it emits is of type string. For more information on EventEmitter , see the EventEmitter API documentation. The addNewItem() function uses the @Output() , newItemEvent , to raise an event with the value the user types into the <input> .
Observables provide support for passing messages between parts of your application. They are used frequently in Angular and are a technique for event handling, asynchronous programming, and handling multiple values.
A callback function is a function passed into another function as an argument which is invoked inside the callee function(here greeting) to complete or after some kind of actions.
Not sure if relevant or if it helps someone: I ran into a similar issue: I wanted to consume a property of type Observable<number>
provided by a component in the parent component.
After reading Observables and Reactive Programming in Angular 2, I noticed that I need to "turn" around my architecture and let the parent create the Observable
and then assign it to the child.
So instead of having a MyComponent
with an @Output()
of type Observable<number>
(which was then initialized to new BehaviorSubject(0)
and modified using calls to next
), I changed MyComponent
to haven an @Input()
of type BehaviorSubject<number>
:
@Component({
selector: 'my-component',
template: `
<button (click)="increment()">Click me!</button>
`,
})
export class MyComponent {
private _count : number = 0;
@Input()
public counter : BehaviorSubject<number>;
public increment() {
this._count++;
if (this.counter)
this.counter.next(this._count);
}
}
The parent now creates a BehaviorSubject and binds to the property. It can easily consume the BehaviorSubject as an Observable:
@Component({
selector: 'my-app',
template: `
<my-component [counter]="count"></my-component>
<span>{{text | async}}</span>
`,
})
export class App {
public text : Observable<string>;
public count : BehaviorSubject<number> = new BehaviorSubject(0);
constructor() {
this.text = this.count.map(n => "Click: " + n);
}
}
Plunker: https://plnkr.co/edit/rKtVWmmGnFn4Po4B4CCL?p=preview
So in your case, I would say that your slider should provide an @Input
(maybe call it value or number) and let the parent assign an observable (instead of letting the child create one).
One of core difference between Angular 1 and Angular 2 is that change detection is always performed from top to bottom. That makes performance much better. Also there is no need to perform "stabilization" ($digest loop) as it was in Angular 1.
In Angular 2 you can't "push" change back in other way, except emitting event with EventEmitter
/Subject
, so Angular 2 can start checking component's Change Detectors.
Here is nice article about this topic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With