Steps for Signing Up for a Collaboration Service

I'm struggling to understand how to monitor for new values in an observable from a service. My ultimate objective is to integrate an interceptor, a service, and a directive to show loading information to the user. I have set up an interceptor to listen for http calls:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse } from '@angular/common/http';
import { Observable, pipe } from 'rxjs';
import { LoadingService } from '../loading.service';
import { map, finalize } from 'rxjs/operators';

@Injectable()
export class LoadingInterceptor implements HttpInterceptor {
  constructor(private loadingSrv: LoadingService) {}

  public intercept(req, next): Observable<HttpEvent<any>> {
    if (req.url === 'graphql') {
      console.log('first', req);
      this.loadingSrv.saveRequest(req);
    }
    return next.handle(req).pipe(
      map(el => {
        if (req.url === 'graphql') {
        }
        return el;
      }),
      finalize(() => {
        console.log('final', req);
      })
    );
  }
}

If a request is detected, it should trigger the loading service and execute a saving function.

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

@Injectable({
  providedIn: 'root'
})
export class LoadingService {
  public loadingQueries: BehaviorSubject<[]> = new BehaviorSubject(null);
  constructor() {}
  saveRequest(req) {
    this.loadingQueries.next(req);
  }
}

The loading service will emit the new request value to the behavior subject. Now, my goal is to subscribe to this BehaviorSubject from a directive.

import { Directive, Input, OnInit, TemplateRef, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { LoadingSpinnerComponent } from './loading-spinner.component';
import { LoadingService } from './loading.service';

@Directive({
  selector: '[showLoadingSpinner]'
})
export class ShowLoadingSpinnerDirective implements OnInit {
  @Input('showLoadingSpinner') query: any;

  constructor(
    private viewContainerRef: ViewContainerRef,
    private templateRef: TemplateRef<any>,
    private loadingSpinner: LoadingSpinnerComponent,
    private factoryResolver: ComponentFactoryResolver,
    public loadingSrv: LoadingService
  ) {}

  ngOnInit(): void {
    const factory = this.factoryResolver.resolveComponentFactory(LoadingSpinnerComponent);
    console.log(this.query);
    this.loadingSrv.loadingQueries.subscribe(console.log);
  }
}

My issue now is that the subscriptions are not recognizing new values. Perhaps because the service here is a new instance? How can I ensure the directive listens for any changes to detect when a query is initiated and completed?

Answer №1

Here is a potential solution that might suit your needs. While I cannot determine the exact issue at hand, my suggestion would be to keep the BehaviorSubject private. Additionally, it is crucial to remember to unsubscribe in your component.

For your loading service:

export interface LoadingState {
  req: any;
}

let _state: LoadingState = {
  req: null,
};

@Injectable({
  providedIn: 'root',
})
export class LoadingService {
  private store = new BehaviorSubject<LoadingState>(_state);
  private state$ = this.store.asObservable();

  req$ = this.state$.pipe(
    map((state) => {
      return state.req;
    }),
    distinctUntilChanged()
  );

  constructor() {}
  saveRequest(req) {
    this.updateState({ ..._state, req });
  }

  private updateState(state: LoadingState) {
    this.store.next((_state = state));
  }
}

In your component:

constructor(private loadingSrv: LoadingService) {}
private onDestroy = new Subject<void>();
req$: Observable<LoadingState> = this.loadingSrv.req$;
ngOnInit() {
this.req$.pipe(takeUntil(this.onDestroy)).subscribe((value) => {
console.log(value);
});
}
ngOnDestroy() {
this.onDestroy.next();
this.onDestroy.complete();
}

Answer №2

To resolve the issue, the decision was made to place the service in a module that is not lazily loaded.

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

Angular2 Window Opener

Trying to establish communication between a child window and parent window in Angular 2, but I'm stuck on how to utilize window.opener for passing a parameter to Angular 2. In my previous experience with Angular 1.5, I referenced something similar he ...

What is the best way to display multiple items on a single page using the Ant Design (NG-Zorro) carousel component?

Hey there, I'm looking for a way to display multiple items per page using the ant design (NG-Zorro) carousel. I found some information on their website here: What I'm aiming for is to have something like this - Multiple Items If you have any i ...

Exploring Angular localization using ng2-smart-table

Currently, I am utilizing ng2-smart-table. In my component.ts file, I am setting the column headings. settings = { actions: { add: false, edit: false, delete: false }, columns: { date: { title: 'Date' ...

Display the column every time the user types something into the search bar

Currently working on an Angular project and I'm trying to figure out how to make the middle column visible whenever the user enters text in the search bar. At the moment, I have a search bar for user input and three flex columns. The middle column is ...

Navigate smoothly through Angular components without any page reloads

Here is a simplified version of my current setup: <app-header></app-header> <app-search></app-search> <router-outlet></router-outlet> <app-footer></app-footer> Within the router-outlet, I have two component ...

Utilizing observable services efficiently in Angular

I have developed a unique service for facilitating communication between various components and modules. @Injectable({ providedIn: 'root' }) export class CommunicationService<T> { private emitChanges = new Subject<T>(); changes ...

In TypeScript, the 'onChange' is declared multiple times, therefore this particular usage will be scrutinized carefully

Within my React project, I am utilizing material-ui, react-hook-form, and Typescript. However, I encountered an error in VSCode when attempting to add the onChange function to a TextField component: 'onChange' is specified more than once, resul ...

Error in VS Code related to Vue Array Prop JSDoc TypeScript: The properties of type 'ArrayConstructor' are not found in type 'MyCustomType[]'

After reading the article "Why I no longer use TypeScript with React and why you might want to switch too", I decided to work on a Vue CLI project using ES6 without TypeScript. Instead, I enabled type checking in Visual Studio Code by utilizing JSDoc / @ty ...

Attempting to utilize a namespace-style import for calling or constructing purposes will result in a runtime failure

Using TypeScript 2.7.2 and VSCode version 1.21 with @types/express, I encountered an issue where in certain cases VSCode would report errors like: A namespace-style import cannot be called or constructed, and will cause a failure at runtime. Interestingly ...

Ways to verify if a value corresponds to a particular data type

Is there a more elegant way for TypeScript to check if a value matches a specific type without actually invoking it, instead of the method described below? Consider the following example: import { OdbEventProcessorFunc } from "./OdbEventProcessor&quo ...

Ways to halt interval in Angular 7

I have a function that emits values continuously. What I desire?? If the Math.sign condition is met, I want to redirect the user to another screen and show a toast message. However, currently the toast message keeps displaying repeatedly because the int ...

Tips on passing an object as data through Angular router navigation:

I currently have a similar route set up: this.router.navigate(["/menu/extra-hour/extra-hours/observations/", id]) The navigation is working fine, but I would like to pass the entire data object to the screen in order to render it using the route. How can ...

Why isn't the background-image displaying with the use of the url() function?

I've been attempting to set an image as the background using background-img:url(imageLing), but it's not working properly. When I inspect the element, it shows me background-image: url(assets/backgrounds/5.jpg);. What could be causing this issue? ...

Resetting md-radio-button choices within an Angular 2 application

My Angular app has a sorting filter using radio buttons via md-radio-group for users to choose how they want data displayed. The radio buttons work fine, but I'm struggling to clear them when the "Restore Defaults" button is clicked. This is the code ...

Experiencing delays with Angular 4 CLI's speed when running ng serve and making updates

After running ng serve, I noticed that the load time is at 34946 ms, which seems pretty slow and is impacting our team's performance. Additionally, when we update our code, it takes too long to reload the page. https://i.sstatic.net/lpTrr.png My Ang ...

Exploring JSON object nesting

I need to extract specific objects (fname, lname, etc.) from the data received in node.js from an Angular front-end. { body: { some: { fname: 'Fuser', lname: 'Luser', userName: 'userDEMO', pas ...

When the route changes, routerCanReuse and routerOnReuse are not invoked

I am currently exploring the functionalities of Angular2's Router, specifically focusing on OnReuse and CanReuse. I have followed the documentation provided here, but I seem to be encountering difficulties in getting the methods to trigger when the ro ...

Error: Reference to an unknown variable causing dependency failure

My Angular project has a CI/CD pipeline that was working fine yesterday. However, today the same code is producing multiple errors during the build process: ./src/styles.scss.webpack[javascript/auto]!=!./node_modules/css-loader/dist/cjs.js??ruleSet[1].rule ...

Trigger an error in TypeScript with an embedded inner error

Is it possible to throw an Error with an inner Error in TypeScript, similar to how it's done in C#? In C#, you can achieve this by catching the exception and throwing a new one with the original exception as its inner exception: try { var a = 3; ...

Enhancing React with TypeScript: Best Practices for Handling Context Default Values

As I dive into learning React, TypeScript, and Context / Hooks, I have decided to create a simple Todo app to practice. However, I'm finding the process of setting up the context to be quite tedious. For instance, every time I need to make a change t ...