No Execution When Subscribing to Observable

I am attempting to showcase messages from a list for a duration of 1 second each. I cannot utilize the interval(1000) method because I need to have the ability to clear a message as soon as a condition is met and then display the subsequent one for 1 second.

My current progress includes:

nextMessage() : Observable<any>{
    this.currentMessage.next(this.messages[this.messagePointer++]);
    return this.currentMessages;
}

subscribeMessage() : void{
    this.currentMessage.pipe(switchMap(_=timer(1000).pipe(map(x=>this.nextMessage())))).subscribe(x=>console.log(x));
}

As it stands, this does not produce any results. My idea was that every second, the nextMessage function would update the currentMessage Observable, and if it was changed externally in between, the Timer would be reset. The subscribe method currently does not output anything, but when I try this instead:

this.currentMessage.pipe(tap(x=>console.log(x)),switchMap(_=timer(1000).pipe(map(x=>this.nextMessage())))).subscribe(x=>console.log(x));

I observe data values being displayed at 1-second intervals with the tap function working. Why does tap work but not the subscribe function?

EDIT

For a demonstration, you can view a StackBlitz Demo here

Answer №1

The issue at hand is the behavior of switchMap: it ends the observable prematurely, preventing the inner observable from emitting.

Here's a breakdown of what's happening:

  1. currentMessage emits a message
  2. tap logs that message
  3. switchMap initiates a 1000ms timer
  4. Once the timer finishes, nextMessage() gets called
  5. nextMessage appends a value to currentMessage
  6. Right before advancing to the next step in nextMessage, currentMessage emits another message (same as step 1)
  7. tap logs this additional message (same as step 2)
  8. switchMap terminates the previous observable and sets a new 1000ms timer
  9. We circle back to nextMessage(), generating an observable that goes unacknowledged due to termination in the prior step
  10. This cycle repeats starting from step 4

A simple solution would be replacing switchMap with mergeMap, but remember to insert take(1) on the inner observable to ensure only one value is emitted:

currentMessage
  .pipe(
    tap(x => console.log('Tap:' + x)),
    mergeMap(_ => timer(1000).pipe(
      map(x => nextMessage()),
      take(1)
    ))
  )
  .subscribe(x => console.log(x));

Although initially intricate, transitioning to a more reactive approach could streamline the process.

If using interval(1000) isn't viable due to reset conditions, consider employing a Subject for effective management of these conditions:

const messageResets = new Subject();

const messages: string[] = ['Message 1', 'Message 2', 'Message 3'];
let messagePointer: number = 0;

console.clear();

messageResets.pipe(
  startWith(null),
  switchMap(() => timer(0, 1000).pipe(
    map(() => messages[messagePointer++ % messages.length])
  ))
).subscribe(x => console.log(x));

Note: timer(0, 1000) operates similarly to interval(1000).

I typically reserve Subjects for handling external actions within the stream, like clearing the current message under uncertain conditions.

Relying on Subjects for managing internal states can become cumbersome over time.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for waiting for and resolving real data within a loop

I need to populate image URLs and their dimensions in the ImageData interface within a typescript project. The function getDimensionsFromImageUrl is asynchronous. How do I create an array of ImageData without using promises? export interface ImageData { ...

Passing `any` or `any[]` as a function parameter in Types

Recently, I've been working on enhancing my validation middleware to accommodate for both classes (any) and arrays (any[]) as input. Initially, this middleware was set up to take in a single class type as an input parameter. However, I managed to modi ...

Bidirectional data binding in model-driven forms

Currently, I am working on a reactive form that includes fields for first name, last name, and display name. The goal is for the display name to automatically populate with the concatenated values of the first and last name. However, as I am still learning ...

What is the best way to dynamically generate and update the content of a select input in an Angular form using reactive programming techniques?

I have successfully developed an Angular reactive form that includes a select field populated dynamically with values retrieved from an API call. In addition, I have managed to patch the form fields with the necessary data. My current challenge is to dyn ...

Utilize JSX attributes across various HTML elements

I'm looking for a solution to efficiently add JSX attributes to multiple elements. Here are the example attributes I want to include: class?: string; id?: string; style?: string; And here are the example elements: namespace JSX { interface Int ...

Discover and allocate personalized entity

My goal is to locate an item in a list and transfer some of its attributes to another item. The code I currently have feels messy and inefficient. this.myResult = {value1: null, value2: null}; this.myArray = [ { a: 'test1', b: 1, c: {subObject1 ...

Managing Observable<Person[]> in ng-bootstrap typeahead instead of Observable<string[]>: a complete guide

I'm new to Angular/Typescript and have a question. I recently tried out the example from Wikipedia in ng-bootstrap typeahead. Instead of using the Wikipedia call, I decided to use a custom REST service that has the following GET endpoint: GET /pers ...

Detecting and clearing custom visual filters in Power BI

Currently, I am developing a unique visual on Microsoft Power BI using d3.js. This customized visual includes a filter effect where selecting filters changes the style properties and adds new items. However, one issue in Power BI is the inability to dete ...

Is there a way to specifically choose the initial element using Angular? "Backend powered by Django"

Hi there! I've set up Django on the back-end to send data to Angular, and I'm trying to display only the first comment from a list in my HTML page. However, when using limitTo, I encountered this error: Failed to compile. src/app/app.component. ...

How can HTML templates be effectively compiled for production purposes?

As I venture into the world of Angular2 development, I have carefully crafted a specific folder structure for my project: components component1 home.component.ts home.component.html home.component.scss To streamline the buildi ...

The error 'TypeError: instances.map is not a function in Angular Loopback' is indicating

Currently, I am utilizing the @mean-expert/loopback-sdk-builder to create my API on Angular 4.3.6. However, I encountered an error when executing the following code snippet: this._userApi.findUsersByRoles([{'name':'cliente'}]).subscrib ...

What is the best way to recycle a single modal in Ionic?

Apologies for the vague title, but I'm facing an issue with creating a single modal to display data from multiple clickable elements, rather than having separate modals for each element. For example, when I click on item 1, its data should be shown in ...

The data type 'AbstractControl | null' cannot be assigned to type 'FormGroup'

I am facing an issue with passing the [formGroup] to child components in Angular. The error message says Type 'AbstractControl | null' is not assignable to type 'FormGroup'. I have double-checked my conditions and initialization, but I ...

In what way can I ensure that both parameters of a function match a particular Union type?

My goal is to develop a function that takes two parameters. The first parameter is a union type, and the second parameter's type depends on the type of the first one. For instance: type Fruit = "Orange" | "Apple" | "Banana"; function doubleFruit< ...

TypeScript integration with T4MVC

Within my ASP.NET MVC (5) project, I utilize T4MVC to avoid using magic strings in my views. While this approach works well, there are instances where I require URLs in my JavaScript or TypeScript code, particularly for AJAX requests. Currently, I rely o ...

Creating a Universal Resolver in Angular (2+) - A Step-by-Step Guide

I have a vision to develop an ultra-generic API Resolver for my application. The goal is to have all "GET" requests, with potential extension to other verbs in the future, utilize this resolver. I aim to pass the URL and request verb to the resolver, allow ...

Error in Directive: NgControl Provider Not Found

I encountered an issue with my Directive while attempting to inject 'NgControl' and received a 'No provider for NgControl' error. Here is the structure of my File Directory: app folder |--directives folder |--myDirec ...

The abundance of options in WebStorm's code completion for Node can be overwhelming

I recently finished a project using NodeJS and TypeScript. I made sure to install the type definition files with 'tsd install node'. The code begins with the following lines: var http = require('http'); var server = http.createServer(. ...

Exploring ways to customize or replace the extended CurrencyPipe type in Angular

I'm currently working on reusing an existing currency pipe from Angular common. My objective is to truncate the .00 when the value is round. Here's the code I've come up with: /** Transform currency string and round it. */ @Pipe({name: &apo ...

What is the best way to combine two arrays by sorting them according to their respective years?

I have two separate arrays: one containing values by year and order ID, and the other with different data. My goal is to combine them into a single array based on the year. let array1 = [{orderId: 1, year: 2020, value: 15}, {orderId: 1, yea ...