The observable did not trigger the next() callback

I'm currently working on incorporating a global loading indicator that can be utilized throughout the entire application. I have created an injectable service with show and hide functions:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class SpinnerOverlayService {
    private loaderSubject = new Subject<any>();


    public loaderState = this.loaderSubject.asObservable();

    constructor() { }

    /**
     * Display the spinner
     */
    show(): void {
        this.loaderSubject.next({ show: true });
    }

    /**
     * Hide the spinner
     */
    hide(): void {
        this.loaderSubject.next({ show: false });
    }
}

This is the code for the spinner overlay component, excluding details about HTML and CSS implementation as they are not relevant here.

import { Component, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { SpinnerOverlayService } from '../spinner-overlay.service';

@Component({
  selector: 'spinner-overlay',
  templateUrl: './spinner-overlay.component.html',
  styleUrls: ['./spinner-overlay.component.scss']
})
export class SpinnerOverlayComponent implements OnInit {

  show = false;

  private _subscription: Subscription;

  constructor(private spinnerOverlayService: SpinnerOverlayService) { }

  ngOnInit(): void {
    this._subscription = this.spinnerOverlayService.loaderState.subscribe((state) => {
        console.log("Subscription triggered.");
        this.show = state.show;
      });
  }

  ngOnDestroy(): void {
    this._subscription.unsubscribe();
  }
}

The issue at hand: In the overlay component's code, I am subscribing to the observable loaderState of the service. However, when I call the show() function which triggers the next() of the observable, the subscription callback does not get activated.

This is how I invoke the show() function in app.component.ts:

ngOnInit() {
               this.spinnerOverlayService.show();
}

Any idea what might be missing? It's unusual that the callback isn't being triggered.

For reference, here is an example in Stackblitz: https://stackblitz.com/edit/angular-7-registration-login-example-2qus3f?file=app%2Fspinner-overlay%2Fspinner-overlay.component.ts

Answer №1

The issue arises when the

this.spinnerOverlayService.show();
is called before the initialization of spinner-overlay. Due to the nature of Subject, late subscribers will not receive any previous values unless there is a new one.

To address this, you can consider switching from using a Subject to a BehaviorSubject, which retains and emits the last value to new subscribers.

Alternatively, you can move the

this.spinnerOverlayService.show();
call within the ngAfterViewInit lifecycle hook. This ensures that spinner-overlay has been initialized and subscribed to
spinnerOverlayService.loaderState
.

ngAfterViewInit() {
  this.spinnerOverlayService.show();
}

Take a look here

Answer №2

Aside from what was mentioned above, you also have the option to integrate a state within your spinnerOverlayService service for toggling visibility and subscribe to a subject for any new values:

public state = { show: false };

    constructor() { }

    /**
     * Display the spinner
     */
    show():void {
      this.state = { show: true };
      this.loaderSubject.next(<any>{ show: true })
    }

    /**
     * Conceal the spinner
     */
    hide():void {
      this.state = { show: false };
      this.loaderSubject.next(<any>{ show: false })
    }

and add this in your ngOnInit:

 ngOnInit(): void {
    if(this.spinnerOverlayService.state.show){
      console.log('Subscription triggered.');
    };
    this._subscription = this.spinnerOverlayService.loaderState.subscribe((state) => {
        console.log("Subscription triggered.");
        this.show = state.show;
      });
  }

Alternatively, you can utilize:

private loaderSubject = new ReplaySubject(1); // to store the last value

demo.

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

Extracting user input from an iframe and transferring it to another frame in HTML format

Can someone advise me on how to extract values from iframe1 and transmit them to iframe2 as HTML? I am open to either JavaScript or jQuery - no preference. As a beginner in javascript, I stumbled upon some code that seems relevant. <!DOCTYPE html> ...

Connect a click event from one component to another component

Can Angular bind a click event dynamically from a component to another existing component on the page? Check out this image for reference. In my app, I have 4 simple components - a shell component that defines the layout, a header component (blue outline) ...

Using TypeScript to utilize an enum that has been declared in a separate file

Imagine I have defined an enum in one file (test1.ts): export enum Colors{ red=1, blue=2, green=3 } Then in another file (test2.ts), I am creating a class with a method. One of the parameters for that method is a Color from the Colors enum: ...

What is the best way to change the value of a div using JavaScript?

i could really use some assistance, i am trying to ensure that only the selected template is shown on the screen, while all others are hidden. The expected outcome should be to replace the values of: <div class="city">City<span>,< ...

Error: The argument provided cannot be assigned to a parameter that requires a string type, as it is currently a number

Currently, I am in the process of migrating some older websites to TypeScript. However, I keep encountering a type error during the build process. The specific error message is Type error: Argument of type 'number' is not assignable to parameter ...

Executing JavaScript function by clicking on <img>

I've been developing a website similar to YouTube, and I'm facing difficulties with the Like/Dislike feature for comments. Currently, I have implemented it in the following way: when a user clicks on an image (thumbsUp.png or thumbsDown.png), a ...

What prevents me from employing my nestjs unique decorator within a constructor?

I am looking to develop a personalized decorator that fetches tenant information. This is the current code snippet I have: export type TenantInfo = { token: string id: string } export const TenantInfo = createParamDecorator( (data: unknown, cont ...

activating a component by interacting with another component

How can I pass the uuid from parent to child component through a click event in Angular? App.component.ts import { Component } from '@angular/core'; import { v4 as uuid } from 'uuid'; @Component({ selector: 'my-app', tem ...

Having difficulty subscribing to multiple observables simultaneously using withLatestFrom

I am facing an issue where I have three observables and need to pass their values to a service as parameters. I attempted to do this using WithLatestFrom(), but it works fine only when all values are observables. this.payment$.pipe( withLatestFrom(this.fir ...

The styling of the CSS is tailored to various breakpoints

source: Display helpers How can I dynamically change CSS styles based on the current breakpoint size? For example, can I set different sizes, positions, and colors for elements when the window is on xs compared to md or other breakpoints? ...

Combining Two JSON Arrays Featuring Unique Keys

I have two JSON arrays with slightly different keys. The first JSON array contains the keys id, name, and title. The second JSON array includes id, title, forename, name, and company. I am wondering if it's possible to merge these two arrays so th ...

Exploring Vue's reactivity using the composition API and cloning props

In my current component setup, I am receiving props from a parent. However, I am facing an issue where I only want to clone these props without any changes affecting the parent component. <template> <input-text v-model="form.name" /&g ...

Using AngularJS to pass radio button value to a $http.post request

Can you please advise on how to extract the value from a radio button and send it using $http.post in AngularJS? Here is an example: HTML <input name="group1" type="radio" id="test1" value="4"/> <label for="test1">Four paintings</label ...

Generate an image, PDF, or screenshot of a webpage with the click of a button

I've been searching for a solution that would enable users to click a button and save an image or PDF of the current page. The content on the page is dynamic and dependent on user input, resulting in sequences displayed in various colors. I'm loo ...

Building secure authentication with Angular, node.js, and an identity provider through SAML integration

Implementing SSO using SAML2 is my goal, but I am facing a challenge with a distributed system where each instance operates independently on its server. There are three instances in the environment: Instance #1: an angular frontend Instance #2: a node.js ...

The Angular2 framework will sometimes send an OPTIONS method request instead of an http.GET when

I am currently attempting to implement basic authentication in my Angular2 application. public login() { // Setting basic auth headers this.defaultHeaders.set('Authorization', 'Basic ' + btoa(this.username + ':' + thi ...

Expand and Collapse Button for Customizing Table Height Individually

I trust everything is going smoothly. A challenge I'm facing involves implementing a button to expand a specific row within a table. Currently, clicking the "show more/show less" button extends all rows when the goal is to do it for each individual ta ...

What are the steps for utilizing the watch feature in Vue.js with TypeScript?

Currently, I am looking to convert this JavaScript script into TypeScript. However, I require the syntax for watchers. export default { props: ['branch_id'], watch: {} } ...

Utilize your access token to send a message through Google Business Messages

Currently, I have successfully set up a method to send messages using the Google Business Messages API from an agent to a user through NodeJS. const bmApi = new businessmessages.businessmessages_v1.Businessmessages({}); This process requires authenticatio ...

Multiple minute delays are causing issues for the Cron server due to the use of setTimeout()

I have an active 'cron' server that is responsible for executing timed commands scheduled in the future. This server is dedicated solely to this task. On my personal laptop, everything runs smoothly and functions are executed on time. However, ...