RxJS ‘repeat’ operator — beginner necromancer guide
Or how to enliven dead Observables…and why

As you may know the RxJS repeat operator restarts a source Observable and applies it a specific number of times. You can read more about it in my article ‘retry vs repeat’.
In other words repeat makes dead (complete) Observables alive again. Ok, but why should I care? Keep reading to find out:-)
Let's consider a learning task that will help us to get deeper in understanding when should we use this necromancer tool.
- On our webpage, we want to track mouse hold and mouse dragging events.
- If the mouse is held more then 2 seconds and doesn’t move — we want to emit the string ‘HOLD’ from a mouse_hold$ observable.
- If the mouse is held less then 2 seconds and starts moving — we want to emit mousemove event values from a mouse_drag$ observable.
Implementation
OK, let's start by creating the 3 main observables we need for our solution that will produce the corresponding mouse event values:
Composing mouse_hold$
OK, now we need to compose mouse_hold$
according to this algorithm:
- When
mouse_Down$
emits a value we should start a 2000ms timer - If the timer emits value in 2000ms— we should emit a string: HOLD
- If
mouse_Up$
ormouse_Move$
emit a value before the 2000ms timer emission — we should completemouse_hold$
For step 1 we will use the RxJS timer function. Usually, it is used for periodic value emissions, but if it is provided with one argument (inactivity duration) — then it emits value (zero) one time only.
const timer$ = timer(2000);
const timer$ = timer(2000);
So for step 2 we should use the switchMap operator to return an Observable that will emit a string: HOLD

Here we make a switch two times: when mouse_Down$
emits — we switch to the timer$
Observable. In 2000ms timer$
will emit and we will switch to an of('HOLD')
Observable. So at the end, the mouse_Hold$
subscribers will get a HOLD string on a 2000ms period.
Now we will implement step 3 — if one of mouse_Up$
or mouse_Move$
emits a value — we should complete the observable. We can reach this by using the merge function (to combine values from both mouse_Up$
or mouse_Move$
) and the takeUntil operator — to complete mouse_Hold$
if any of them emits.

Composing mouse_drags$
OK, now we need to compose mouse_drags$ according to the following algorithm:
- When
mouse_Down$
emits a value, we start waiting for both themouse_hold$
andmouse_move$
observables. - If
mouse_move$
emits (beforemouse_hold$
emits)— we should continue re-emitting the mousemove event object (our main goal actually). - If
mouse_Up$
ormouse_hold$
emit a value — we should complete mouse_drags$.
As in the previous example for step 1 we will use switchMap.
For step 2 we will use switchMap as in a previous example.
mouse_drags$ = mouse_Down$.pipe(
switchMap((time) => mouse_Move$)
)
For step 4 we will use takeUntil and merge as we did in a previous example:
mouse_drags$ = mouse_Down$.pipe(
switchMap((time) => mouse_Move$,
takeUntil(merge(mouse_Up$, mouse_Hold$)),
)
Seems like it is done, isn’t it?
Packtpub.com and I prepared a whole RxJS course with many other details of how you can solve your every-day developer’s tasks with this amazing library. It can be interesting for beginners but also contains advanced topics. Take a look!
And what does the necromancy?
Now let's try to subscribe to the created observables (mouse_drags$ and mouse_hold$) and run this code (you can find out why we should subscribe to run it in my other article).
Well, if you try to run this code in a codepen (Run and then just press a mouse button for more then 2 seconds), it will work only once.

But why?!!!
Because the takeUntil operator completes the sequences. And we should restart these dead observables to make them wait for the mousedown event again.
First I want to try some magic words!

Unfortunately no, that didn't help…
OK, then the last method — I should put a call into the main RxJS necromancer:

So, all we need to do — is to use the repeat s̵p̵e̵l̵l̵ operator from the main spellbook.

Let's run it in a codepen — and now this works as expected!

How does ‘repeat’ work?
Let's take a look at how it is implemented in the RxJS GitHub repo:

Aha, these spells are really not so hard to understand:-) We count the number times the source$
observable runs. If it is more then 0 — we subscribe to source$
again.
Conclusion
- repeat can help with making dead observables alive again.
- You can read more about the repeat logic in RxJS in the article ‘retry vs repeat’.
- Take a look at an interesting video “RxJS By Example” of RxJS Core team lead — Ben Lesh
- Live fast, code clean!
Like this article? Let's keep in touch on Twitter.
Starting from section 4 of my RxJS video course advances staff is reviewed — so if you familiar with RxJS already — you can find something useful for you as well: higher-order observables, anti-patterns, schedulers, unit testing, etc! Give it a try!
Special thanks to Alex Okrushko and Nicholas Jamieson for reviewing my article!