Steven Luke Steven Luke - 3 months ago 113
TypeScript Question

Typescript + Angular2: Subscribing to Observable causes "Unrecognized teardown 1" error

I have an issue with using an Observable in an Angular2.rc.4 Typescript app. I have a plunker for it here:
https://embed.plnkr.co/UjcdCmN6hSkdKt27ezyI/

Essentially the app has a service which has this code:

private messageSender : Observable<string>;

constructor() {
this.messageSender = Observable.create(observer => this.clients.push(observer));
}

public listenForMessages() : any {
console.log("Listen Requested...")
return this.messageSender;
}


And I want to listen to it from a component:

ngOnInit() {
this.chatter.listenForMessages().subscribe(msg => console.log(msg));
}


This gives me the following error:

EXCEPTION: Error: Unrecognized teardown 1 added to Subscription.
Error: Unrecognized teardown 1 added to Subscription.
at Subscriber.Subscription.add (Subscription.ts:151)
at Observable.subscribe (Observable.ts:93)
at LoginPage.ngOnInit (login.ts:15)
at DebugAppView._View_LoginPage_Host0.detectChangesInternal (LoginPage.template.js:29)
at DebugAppView.AppView.detectChanges (view.ts:261)
at DebugAppView.detectChanges (view.ts:377)
at DebugAppView.AppView.detectContentChildrenChanges (view.ts:280)
at DebugAppView.AppView.detectChangesInternal (view.ts:272)
at DebugAppView.AppView.detectChanges (view.ts:261)
at DebugAppView.detectChanges (view.ts:377)
BrowserDomAdapter.logError @ browser_adapter.ts:82


The same error occurs if a transpile tsc or allow that to happen in the browser, and if I target either ES6 or ES5.

I have been looking at it for hours, I have found no references to it on any other site. That error message comes from RxJS, it examines the thing passed into the .subscribe() method, checks if its type is 'object' or 'function' and will emit this error if it is neither. I have passed lambdas as in the plunker, or pre-defined functions and they result in the same problem.

Any ideas? If I create the Observable in the component, then there is no problem. If I subscribe in the service then I get the same error... So confused.

Answer

Your issue is that Array#push returns a number (which is the new length of the Array) and it is trying to use that as the new TeardownLogic when you do Observable.create(observer => this.clients.push(observer)).

I suggest that you do not use the observer-array pattern, you are just reinventing the wheel honestly and it is unlikely that you will do it properly (*note: it isn't just you, I've seen it popping up in ng2 tutorials and it is just a awful, awful pattern).

If you need multi-cast behavior you should be using a Subject instead:

private messageSender : Subject<string>;

constructor() {
    this.messageSender = new Subject<string>();
 }

public listenForMessages() : any {
    console.log("Listen Requested...")
    return this.messageSender.asObservable();
}

An even better solution would be to do away with the intermediate Subject altogether and subscribe directly to the message source, but without knowing more about your application I can't actually say how you might hook that up.