Create your own
Lesson illustration

Creating Observables from Various Sources

Hello! Welcome back.

In our previous lesson, we explored the critical distinction between cold and hot Observables, establishing that the key difference lies in where the producer of values is managed. Cold Observables create a new producer for each subscriber (unicast), while hot Observables share a single, external producer among all subscribers (multicast).

Today, we'll put that knowledge to practical use. We will learn how to create Observables from the most common data sources you'll encounter in web development: static data, promises, and DOM events. This is the first step in bringing data into the reactive world of RxJS.

Our goal is to master three fundamental creation functions: of, from, and fromEvent. As we go through each one, I'll ask you to consider whether it creates a cold or a hot Observable, reinforcing what we learned last time.

1. Creating Observables from Static Values: of

The simplest way to create an Observable is from a set of static values you already have. The of function is designed for this. It takes any number of arguments, emits each one in sequence, and then immediately issues a complete notification.

For example, of(1, 'hello', {id: 3}) will create an Observable that emits:

  1. The number 1
  2. The string 'hello'
  3. The object {id: 3}
  4. A complete signal

A common point of confusion is how of handles arrays. If you pass an array as a single argument, of will emit the entire array as a single item.

import { of } from 'rxjs';

// Emits three separate numbers, then completes
const numbers$ = of(1, 2, 3);
numbers$.subscribe({
  next: val => console.log('of(1,2,3) next:', val),
  complete: () => console.log('of(1,2,3) complete')
});
// LOGS:
// of(1,2,3) next: 1
// of(1,2,3) next: 2
// of(1,2,3) next: 3
// of(1,2,3) complete

// Emits one item (the array), then completes
const array$ = of([1, 2, 3]);
array$.subscribe({
  next: val => console.log('of([1,2,3]) next:', val),
  complete: () => console.log('of([1,2,3]) complete')
});
// LOGS:
// of([1,2,3]) next: [1, 2, 3]
// of([1,2,3]) complete

Based on this behavior, would you classify an Observable created with of as cold or hot?

Answer It's **cold**. The producer is the list of arguments provided to `of`. Every time a new observer subscribes, the Observable will iterate through this list and emit the values from the beginning, creating a new, independent execution for that subscriber.

2. Converting Other Data Types: from

The from function is a more versatile creation tool. It can convert a wide range of data structures into an Observable. We'll focus on its two most common uses: converting iterables (like arrays) and converting promises.

2.1. from with Iterables

When you pass an iterable (e.g., an array, a string, a Map, or a Set) to from, it creates an Observable that emits each item from the iterable one by one.

This is where the contrast with of becomes clear:

  • of([1, 2, 3]) emits the array [1, 2, 3] as a single value.
  • from([1, 2, 3]) emits 1, then 2, then 3 as three separate values.

The following video provides a clear demonstration of both of and from so you can see the difference in action.

Beginner's RxJS Tutorial: Dive Deep with RxJS Crash Course!

This segment from the 'Beginner's RxJS Tutorial' by Monsterlessons Academy clearly demonstrates the use of of and from with an array, highlighting their different emission behaviors.

Watch the operators introduction and then handling plain data. Pay close attention to the console output when the code switches from of to from. This will solidify your understanding of how they handle array-like data.

Given your background, you can think of from as a way to "unpack" a collection into a sequence of discrete emissions over time, whereas of "wraps" its arguments into a sequence of emissions.

2.2. from with Promises

Integrating with existing asynchronous code is crucial, and from is the standard tool for converting a Promise into an Observable.

When you pass a promise to from, the resulting Observable will:

  1. Wait for the promise to resolve.
  2. Emit the resolved value as its single next notification.
  3. Immediately complete.
  4. If the promise rejects, the Observable will emit an error notification.

It is critical to use from for this, not of. Using of(myPromise) would simply emit the Promise object itself, not its resolved value.

This next video segment explains this concept perfectly.

Beginner's RxJS Tutorial: Dive Deep with RxJS Crash Course!

Continuing with the same tutorial, this part demonstrates how to correctly convert a Promise to an Observable and explicitly shows the incorrect result of using of.

Watch the promises demonstration. The key takeaway is the difference in output between from(promise) and of(promise). This is a common mistake for beginners.

A note on the cold vs. hot nature of from(promise): This is a nuanced case. A Promise is eager—it begins its work the moment it is created. However, the Observable wrapper created by from is still lazy. It only starts listening for the promise's resolution when you subscribe. Because the underlying promise is already in flight and will only resolve to a single value, all subscribers to the Observable will receive the same value. This makes it behave like a hot source in terms of the value, but the subscription model is still lazy/cold.

3. Creating Observables from Events: fromEvent

So far, we've dealt with data that we already have (static values, arrays) or that will exist at a single point in the future (promises). But what about streams of events that can happen at any time, like user input?

This is the purpose of fromEvent. It creates an Observable that emits values whenever a specific event occurs on a given target. This is your gateway to making user interactions reactive.

The most common usage is with DOM elements:
fromEvent(document.getElementById('myButton'), 'click')

This creates an Observable that emits the DOM MouseEvent object every time the button is clicked.

This is a perfect example of a hot Observable. The browser's event loop is the external producer, firing click events whether your code is subscribed or not. When you subscribe to a fromEvent Observable, you are simply tapping into this existing stream of events.

The following video gives an excellent, practical demonstration of using fromEvent for various DOM events.

RxJS Observables Crash Course

This clip from Traversy Media's 'RxJS Observables Crash Course' provides a great developer-focused look at fromEvent, covering clicks, keyboard input, and mouse movement.

Watch the segment on UI event observables. Notice how you can access properties of the emitted event object (like e.target.value for an input field) to get the data you need. This is a fundamental pattern in RxJS.

As you can see, fromEvent is incredibly powerful for handling user interactions, forming the basis for features like type-ahead search boxes, drag-and-drop interfaces, and more.

Conclusion

You've now learned the three most essential ways to bring data into an RxJS stream. These creation functions are the foundation upon which all other reactive logic is built.

Key Takeaways:

  • of: Creates a cold Observable that emits a sequence of arguments you provide. It's for simple, known, finite sequences.
  • from: Creates a cold Observable by converting an iterable (like an array) or a promise. It unpacks the source into a sequence of emissions.
  • fromEvent: Creates a hot Observable that listens for events on a target. It's for handling asynchronous, user-driven, or external event sources.

Here is a summary table:

FunctionInput TypeEmission BehaviorType
ofSequence of values (a, b, c)Emits a, then b, then cCold
fromIterable ([a, b, c])Emits a, then b, then cCold
fromPromise <value>Emits value when resolvedCold (lazy subscription to an eager source)
fromEventEvent Target + Event NameEmits Event object on each triggerHot

In our next lesson, we will continue exploring creation operators by looking at functions that generate Observables based on time: interval and timer. We will also cover defer, a powerful operator for controlling when a cold Observable's subscription begins.

Can't find a good explanation? Sign up and we'll make it for you

Sign up