Skip to main content
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with: Alec Irwin
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with: Alec Irwin

Converting A Subject To An Observable Using RxJS In Angular 2

By
Published in Comments (10)

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.

Want to use code from this post? Check out the license.

Reader Comments

15 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

15,811 Comments

@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

15,811 Comments

@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.

15,811 Comments

@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).

2 Comments

@RajeshRaja,

If you know who emits/produces event data, you can wrap that producer inside an Observable object.

If you don't know the producer, or don't care who produces the event data, use a Subject.

In my case, I model a viewless layer first. I don't care who produces a button press. It might be a test or a DOM button, or via console.
If I always used a DOM button, I could use an Observable instead.

1 Comments

This is great analysis of the observable. I always feel like that about classes and methods descriptions and also about explanations people post about the functionality of any framework: They're odd and don't really explain anything. The explanations are always metaphorical as if they were going to be read by someone that doesn't know anything about coding instead of developers. And as a developer I need the technical stuff to understand how the code works.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel