Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at the jQuery Conference 2010 (Boston, MA) with: Richard Worth
Ben Nadel at the jQuery Conference 2010 (Boston, MA) with: Richard Worth@rworth )

Converting A Subject To An Observable Using RxJS In Angular 2

By Ben Nadel on

In Angular 2, you can use the Rx.Subject class to create the source of an observable sequence. But, you never want to return an Rx.Subject instance to the calling context. Doing so would be somewhat akin to returning a Deferred object rather than a promise; and, it would leave the Subject open to unanticipated and corrupting usage. As such, when exposing a Subject, you'll probably want to convert it to an Observable first.


 
 
 

 
 
 
 
 

Run this demo in my JavaScript Demos project on GitHub.

Up until now, as a newcomer to RxJS, I've been trying to do this - converting a Subject to an Observable - using the Rx.Observable.from() creation method. Unfortunately, while it appeared as if it was working (in the way that I intended), it actually was not. To demonstrate, we're going to use Rx.Observable.from() to try and convert a Subject to an Observable and then test whether or not we can call the .next() method on the result (if all goes well, we shouldn't be able to):

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  •  
  • <title>
  • Converting A Subject To An Observable Using RxJS In Angular 2 Beta 9
  • </title>
  • </head>
  • <body>
  •  
  • <h1>
  • Converting A Subject To An Observable Using RxJS In Angular 2 Beta 9
  • </h1>
  •  
  • <h2>
  • Using Rx.Observable.from()
  • </h2>
  •  
  • <!-- Load demo scripts. -->
  • <script type="text/javascript" src="../../vendor/angularjs-2-beta/9/es6-shim.min.js"></script>
  • <script type="text/javascript" src="../../vendor/angularjs-2-beta/9/Rx.umd.min.js"></script>
  • <script type="text/javascript">
  •  
  • // I return a "hot" observable sequence that emits a value every 1,000 ms.
  • function getObservable() {
  •  
  • var source = new Rx.Subject();
  •  
  • setInterval(
  • function emitNextValue() {
  •  
  • source.next( new Date().getTime() );
  •  
  • },
  • 1000
  • );
  •  
  • // In an attempt to protect the "Subject" from the calling context (such that
  • // the calling context cannot corrupt the Subject by explicitly invoking the
  • // .next(), .complete(), or error() methods), we are going to try to create
  • // an Observable from the Subject.
  • // --
  • // CAUTION: This DOES NOT WORK - the Subject is passed-through because it is
  • // technically already an Observable.
  • return( Rx.Observable.from( source ) );
  •  
  • }
  •  
  •  
  • // --------------------------------------------------------------------------- //
  • // --------------------------------------------------------------------------- //
  •  
  •  
  • var stream = getObservable();
  •  
  • // Subscribe to the observable sequence so we can debug the values.
  • stream
  • .take( 3 )
  • .subscribe(
  • function handleValue( value ) {
  •  
  • console.log( "Observable value:", value );
  •  
  • }
  • )
  • ;
  •  
  • // The value returned from getObservable() is supposed to be an Observable,
  • // which means that we SHOULD NOT BE ABLE to call the .next() method on it.
  • // Let's test it out!
  • try {
  •  
  • stream.next( "foo" ); // Expecting this to throw an undefined method error.
  •  
  • console.warn( "Not good! You were able to call .next() on the stream." );
  •  
  • } catch ( error ) {
  •  
  • console.info( "Thank goodness! You weren't able to call .next() on the stream." );
  •  
  • }
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, the getObservable() method is passing the internal Subject reference through the Rx.Observable.from() method. However, when we run this code, we get the following output:


 
 
 

 
 Converting an RxJS Subject to an Observable sequence. 
 
 
 

As you can see, we were able to invoke the .next() method on the returned value which means that we accidentally returned the Subject back to the calling context. In essence, the Rx.Observable.from() method didn't do anything. And, in fact, if you look at the RxJS source code, you will see that this method will simply pass-through the given object if it is already an instance of the Observable class (which, of course, Subject is by way of inheritance).

The reason that I thought this was working was because the resultant value acts like an Observable. But, that's only because Subject is already an Observable.

So, basically, I've been wrong up until now (and will try to go back and correct some code).

To get this working in the way that we actually intended it to, we can use the Rx.Observable.prototype.asObservable() instance method. I actually saw this method a while back, but the description didn't make sense to me at the time:

Hides the identity of an observable sequence.

Why would I ever want to "hide" the identity of an observable? Seems like such an odd gesture. Until you remember that other classes can extend Observable. Then, it starts to make a little bit more sense. Though, I might rephrase it to be something like:

(Ben's version) Casts any object that implements the observable interface into a new Observable instance.

When you think about it that way, it's exactly what we want - to cast Subject (which implements Observable by way of inheritance) to Observable. So, let's give it a try:

  • <!doctype html>
  • <html>
  • <head>
  • <meta charset="utf-8" />
  •  
  • <title>
  • Converting A Subject To An Observable Using RxJS In Angular 2 Beta 9
  • </title>
  • </head>
  • <body>
  •  
  • <h1>
  • Converting A Subject To An Observable Using RxJS In Angular 2 Beta 9
  • </h1>
  •  
  • <h2>
  • Using Rx.Observable.prototype.asObservable()
  • </h2>
  •  
  • <!-- Load demo scripts. -->
  • <script type="text/javascript" src="../../vendor/angularjs-2-beta/9/es6-shim.min.js"></script>
  • <script type="text/javascript" src="../../vendor/angularjs-2-beta/9/Rx.umd.min.js"></script>
  • <script type="text/javascript">
  •  
  • // I return a "hot" observable sequence that emits a value every 1,000 ms.
  • function getObservable() {
  •  
  • var source = new Rx.Subject();
  •  
  • setInterval(
  • function emitNextValue() {
  •  
  • source.next( new Date().getTime() );
  •  
  • },
  • 1000
  • );
  •  
  • // In an attempt to protect the "Subject" from the calling context (such that
  • // the calling context cannot corrupt the Subject by explicitly invoking the
  • // .next(), .complete(), or error() methods), we are going to try to create
  • // an Observable from the Subject.
  • return( source.asObservable() );
  •  
  • }
  •  
  •  
  • // --------------------------------------------------------------------------- //
  • // --------------------------------------------------------------------------- //
  •  
  •  
  • var stream = getObservable();
  •  
  • // Subscribe to the observable sequence so we can debug the values.
  • stream
  • .take( 3 )
  • .subscribe(
  • function handleValue( value ) {
  •  
  • console.log( "Observable value:", value );
  •  
  • }
  • )
  • ;
  •  
  • // The value returned from getObservable() is supposed to be an Observable,
  • // which means that we SHOULD NOT BE ABLE to call the .next() method on it.
  • // Let's test it out!
  • try {
  •  
  • stream.next( "foo" ); // Expecting this to throw an undefined method error.
  •  
  • console.warn( "Not good! You were able to call .next() on the stream." );
  •  
  • } catch ( error ) {
  •  
  • console.info( "Thank goodness! You weren't able to call .next() on the stream." );
  •  
  • }
  •  
  • </script>
  •  
  • </body>
  • </html>

Now, when we run the above code, we get the following output:


 
 
 

 
 Converting an RxJS Subject to an Observable sequence. 
 
 
 

As you can see, when we tried to call .next() on the returned value, an error was thrown. This is because we successfully converted the Subject instance to an Observable instance, shielding the calling context from the Subject implementation.

While you can technically pass around instances of Subject, doing so allows implementation details to bleed into other parts of the application. To prevent this, it is best to convert Subjects to Observables so that the sequence is exposed in a read-only fashion. Luckily, this is quite easy to accomplish with the .asObservable() instance method inherited by the Subject class in RxJS.




Reader Comments

It's interesting to read your perspective on this kind of thing because coming from .NET it's common to expose implementation types as interfaces that hide what functionality is available. So if you had a private Subject instance you could simply expose it as an IObservable type (I'm paraphrasing a bit here) and consumers couldn't access any of the subject-specific methods on it. There's no need to call a method/function to map it to something new.

For what it's worth, in researching more about this I came across this blurb about how the asObservable() function was not in the latest rxjs 5 code until recently:

http://stackoverflow.com/a/35232664/571237

Reply to this Comment

@Sam,

That's a really interesting feature of .net. I'm not a .net developer; but, I didn't know that any language actually did stuff like that. Very cool.

Thanks for the link to SO. I can't tell you how much Googling I did for "convert Subject to Observable" and NEVER came across that thread. Not sure why - that's exactly what I was looking for. It's not often that Google fails me :D

Reply to this Comment

@Marcus,

Awesome - just be careful that the first example in the blog is intended to NOT work - only the second approach is really doing what we want.

Reply to this Comment

@Black,

That is a great question. And, unfortunately, not one that I feel like I have enough experience to answer. In fact, when I started getting into RxJS (which was only with Angular 2), I did some Googling on that very question. Here's the best post that I could find on the matter:

http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx

A good bit of that post kind of goes over my head, given my limited understanding of RxJS as it is. And, to be honest, I didn't necessarily come away from the post with a solid answer in my head. It sounds like people frown upon the Subject from a performance stand-point; but, the reality is, we're not creating some massive number of Subjects -- just a handful. As such, any performance-based argument seems like its moot.

My model I have in my head now is that *I* have to generate the initial events, I use Subject. But, if I already have an Observable to work with, I'll just tried to chain onto it in some way. But, I don't have any negative bias against Subject for any reason (as others might have).

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.