Prepend/Append Data with RxJS Operators concat and startWith

André Staltz
InstructorAndré Staltz
Share this video with your friends

Social Share Links

Send Tweet
Published 8 years ago
Updated 3 years ago

Some Observables may complete, and we may want to append another Observable to the one which just completed. This lesson teaches you how to use the concat() operator for either appending or prepending, and how the shortcut operator startWith() is an easy way of prepending values to an Observable.

🚨 Since we are importing interval from RxJS, we don't need to preface our Observables with Rx.Observable. You can no longer .{operator}, you need to .pipe({operator}) instead.

[00:00] We know that some observables may complete, such as this observable, foo. Once it completes, it will never again emit anything else to the observer, but it would be useful if we could somehow continue this observable or essentially replace the completion with more values.

[00:17] That's the idea of concatenation. We have concatenation for arrays. There's also concatenation for observables.

[00:24] Let's say you have foo, and you want to concatenate it with this other observable that emits, "4, 5, 6, 7, 8, 9," and then it completes. This observable, as you can see, it emits everything synchronously, so all of this happens in just one of these time frames.

[00:41] I'm going to call this one here "more." We can create it by using the of operator. "4, 5, 6, 7, 8, 9." That is now the observable more.

[00:57] It doesn't happen at the same time, because observables only happen once you subscribe. What we want to do is we want to put it at the end here. When this one completes, we want to replace this completion with this more observable. We do that with concat.

[01:18] We get foo, and we can concatenate it with more. Once we do that, we get, as an output here, this observable that looks like this. It has, "01, 2, 3." Once the foo ends, it will subscribe to more, and it will emit immediately, "4, 5, 6, 7, 8, 9," and then it will complete. That's how of works. Of just emits all of these synchronously, immediately.

[01:46] We're going to see here -- once we subscribe to bar -- "01, 2, 3." Once it hits three, it will emit also, "4, 5, 6, 7, 8, 9." Let's see that. Like that.

[02:04] There's another way you can use concat. Here, we used concat as an instance operator of foo providing more observables, but we can also use the so-called static concat operator, where it's just a function attached to the observable type. You specify all the observables that you want to concatenate together here.

[02:25] If you prefer the API that looks like array.concat, then we can just do foo.concat with more observables. Concat is quite useful when you have finite observables. You need to keep that in mind.

[02:39] Another thing that concat can do, which is quite nice, it allows us not only to append values -- as you can see, we are appending more with foo -- but also to prepend values at the beginning if we so wish.

[02:54] Let's see how we can do that with concatenation. Foo is an observable that doesn't emit a value immediately, but it takes a while. After some while, it will deliver the first value, which is "0What if we wanted to have a value immediately at the beginning of foo? Let's say the string "A." How do we achieve that?

[03:13] We can prepend a value to this foo, but we need to have this "A" string as one observable. How do we do that? We can use also of to simply deliver the string "A." After that, it just completes. Let's call this now "prefix."

[03:32] If you plot prefix in time, it will deliver the string "A," and then it will immediately complete. All of this happens synchronously. That's why it's in parentheses, to indicate that all of this happened in just one of these time frames here that takes just one character. Let's call this one here "prefix."

[03:54] All we need to do is just concatenate. Instead of foo being here in front, we have prefix being here and foo later. That's how foo is being prepended with this prefix.

[04:06] The output here is we deliver "A," and then the completion, but that is immediately replaced with foo. That's what concat does. Then, we get this.

[04:19] Once we run this, when I click run, it will immediately deliver "A," and then after a while will deliver, "01, 2, 3," like that.

[04:28] Because prepending with just one value is quite common, there is a shortcut for this which is called startWith. What we need to do is just call startWith on foo, giving that value A. That does really the same thing that we had here, but it creates this prefix observable for this value here for us. It's not actually prefix.

[04:59] It's not receiving an observable. StartWith doesn't receive an observable, but it just receives that value directly. Internally in startWith, it will create this prefix observable, so we don't need to think about prefix anymore. We just need to call startWith giving the string, and then internally, it will create that small observable and put it in front of foo.

[05:24] StartWith will do the same thing that we had before, immediately delivers "A" and then we see the values.

[05:32] In general, concatenation is quite useful when you have finite observables. You can put them together one after the other. It's also important with infinite observables.

[05:43] Prepending doesn't really assume that foo completes. We could actually make foo be an infinite observable. Foo is just this interval. It ticks every half a second. We can start with A, and then it keeps on going forever. It's only required that this prefix is finite, but then after it completes, we will see this infinite observable.

[06:13] As we can see, it delivers immediately "A," and then it keeps on ticking forever. These are the two big applications of concatenation.

Jon
Jon
~ 7 years ago

var bar = foo.startWith('a'); gives me a TypeScript compile error: Argument of type 'string' is not assignable to parameter of type 'number | Scheduler'.

However, changing it to var bar = foo.startWith(1); gives me no such error. Thoughts?

André Staltz
André Staltzinstructor
~ 7 years ago

Hi Jon. With TypeScript, you would need to declare foo as Observable<string | number>, because otherwise it will infer that foo has type Observable<number> and we can't pretend a string is a number. Observable<string | number> means "this observable may emit either strings or numbers".

ganqqwerty
ganqqwerty
~ 6 years ago

amazing, I finally understand startWith!!!

Markdown supported.
Become a member to join the discussionEnroll Today