"Once the queryParams have been updated, the ActivatedRoute.queryParams event is triggered once

Within my Angular component, I am making an API call by passing a hash string extracted from the current query parameters. Upon receiving the API result, a new hash is also obtained and set as the new hash query parameter. Subsequently, the next API call will be made with this new hash value. A simplified (mock) version of the code snippet is presented below:

import { Component} from '@angular/core';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { Observable, filter, first, mergeMap, of } from 'rxjs';

export class ResourceTableComponent{
  constructor(
    private readonly route: ActivatedRoute,
    private readonly router: Router
  ) {}

  protected hash = firstValueFrom(
    this.route.queryParams.pipe(
      filter((params) => 'hash' in params),
      mergeMap((params) => this.fetch(params['hash'])),
      mergeMap((hash) =>
        this.setQueryParams({ hash }).then(() => hash)
      )
    )
  );

  protected fetch(hash: string): Observable<string> {
    console.log('fetch', hash);
    return of(Date.now().toString());
  }

  private setQueryParams(queryParams: Params): Promise<boolean> {
    return this.router.navigate([], {
      queryParams,
      queryParamsHandling: 'merge',
    });
  }
}

The issue arises where the fetch function is called four times as evidenced by the following logged output:

fetch 1691227799752
fetch 1691228130070
fetch 1691228130110
fetch 1691228130131

The desired behavior is for fetch to be invoked only once, update the hash query parameter with the result, and trigger subsequent calls to fetch only upon page reload or external call.

To achieve this, using first() is one possible solution:

this.route.queryParams.pipe(
  filter((params) => 'hash' in params),
  first(),                                              // <- rxjs first()
  mergeMap((params) => this.fetch(params['hash'])),
  mergeMap((hash) =>
    this.setQueryParams({ hash }).then(() => hash)
  )
)

However, it does raise the question of why such intervention is necessary. While acknowledging that queryParams behaves as a BehaviorSubject, considerations have been made regarding its emission cycle to comprehend the reason for the observed scenario involving multiple calls.

Answer â„–1

Essentially, the function this.setQueryParams triggers an update to this.route.queryParams. Typically, since rxjs streams are synchronous, all synchronous operations are performed immediately, leading to the repeated execution of this.setQueryParams.

Why does it stop at 4? The exact reason can vary based on the specific code, API response times, and the time taken for asynchronous route changes to be executed. The process halts once the stream emits its first value, which is then consumed with the assistance of the firstValueFrom helper function. This results in the entire stream unsubscribing and terminating - meaning no further calls are made.

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

Is it possible to showcase a variety of values in mat-select?

Is it possible to pass different values to the .ts file in each function? For example, can I emit a String with (selectionChange)="onChangeLogr($event)" and an object with (onSelectionChange)="onChangeLogr_($event)"? How would I go about doing this? ...

Passing an event from onSubmit in React without using lambdas

Within our current project, the tslint rule jsx-no-lambda is in place. When attempting to capture event from onSubmit, this is how I typically write my code: public handleLogin = (event: React.FormEvent<HTMLFormElement>) => { event.preventDe ...

Discovering the type in Typescript by specifying a function parameter to an Interface

Consider this sample interface: interface MyInterface { x: AnotherThing; y: AnotherThingElse; } Suppose we make the following call: const obj: MyInterface = { x: {...}, y: {...}, } const fetchValue = (property: keyof MyInterface) => { ...

Submitting a value to ngForm: A step-by-step guide

I am working on an ngForm within Angular Material that contains several input fields. I want to include a new field called total in the submission, but this field is not an input field. It should be a readonly field and its value needs to come from the Typ ...

Following the migration to Typescript, the React component is having trouble locating the redux store props and actions

Here is the structure of my app: export default class App extends Component { render() { return ( <Provider store={store}> <Router> <Header/> ...

Are React component properties enclosed in curly braces?

I have a new component configured like this: type customType = differentType<uniqueType1, uniqueType2, uniqueType3>; function customComponent({q}: customType) When called, it looks like this: <customComponent {...myCustomVar} />, where myCus ...

Using class variance authority variants allows for the acceptance of a "null" value, although it is not recommended

My approach with cva is as follows: const checkboxOptions = cva('border ...', { variants: { size: { sm: 'h-4 w-4', md: 'h-5 w-5', lg: 'h-6 w-6', }, }, defaultVariants: ...

Issues encountered when attempting to add a new user on Firebase

I am facing an issue with this function that is supposed to add new users to my firebase database, but for some reason, it's not working. exports.createUserWithEmailAndPassword = functions.https.onCall( async(data, context) => { const { ...

Angular - Turn off date selection in datepicker when toggle switch is activated

I am currently utilizing angular material and I need to figure out how to deactivate the datepicker after toggling a slide. Below is my upload form equipped with a datepicker: <form #uploadForm="ngForm" (keydown.enter)="$event.preventDefault()" (ngSub ...

Webpack issue arising from the latest Angular update

Each time I initiate ng serve, I encounter the following error. This was not an issue with Angular 11. Generating browser application bundles...Warning: Entry point '@ngbmodule/material-carousel' contains deep imports into 'C:/Users/Göbölà ...

What is the most efficient way to simultaneously check multiple variables for undefined values?

Before executing my code, I need to ensure that none of the variables in a given list are undefined. In the code snippet below, there are 4 variables with uncertain values. While I can manually check variables a and b to satisfy TypeScript's requirem ...

Attempting to utilize pdf.js may result in an error specifying that pdf.getPage is not a recognized function

After installing pdfjs-dist, I attempted to extract all text from a specific PDF file using Node and pdfjs. Here is the code I used: import pdfjs from 'pdfjs-dist/build/pdf.js'; import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry.js&a ...

What is the process for passing input values to a dynamic Angular component?

https://i.sstatic.net/hghse.png My goal is to develop a dynamic filtering system where users can specify multiple attributes and their corresponding values to filter a list of components. The dynamically added component includes two dropdown menus: one fo ...

Is there a way to verify the presence of a collection in firestore?

Is there a way to check if a collection exists in Firestore or not? There is a method to check if a document exists, like so: this.afs.doc('users/' + userId).ref.get().then((doc) => { if (doc.exists) { console.log("User already e ...

Discovering the element on which the value has decreased - a helpful guide

I am attempting to create a drag and drop feature for simple calculations. Users can drag the UP value and drop it on either BH or OT. The issue I'm facing is that I cannot identify the ID where the user dropped, and the onDrop() function is not work ...

Adding a declaration file to a package that relies on an external declaration file can be achieved by following these

In the process of developing a library that relies on another package lacking a declaration file in its npm package, I have successfully installed the necessary declaration file with typings. Everything seems to be working well. Yet, the question remains: ...

Ways to generate an Angular 7 component

Seeking guidance on creating an angular 7 component. I have forked a jsFiddle at this link: https://jsfiddle.net/gauravshrestha/fdxsywLv/. The chart in the fiddle allows data points to be dragged up and down. My goal is to convert this into a component whe ...

How can you initialize Boostrap components or Materialize css in Angular 5 without using any external libraries?

I am a beginner exploring the world of Typescript and Angular. I am curious about how to initialize Bootstrap elements in an Angular-friendly manner without using the ngx-Bootstrap wrapper. For instance, if I wish to initiate a Bootstrap carousel. As per ...

The usage of Angular Tap is no longer recommended or supported

My Angular application contains the following HTTP interceptor: import { Observable } from 'rxjs'; import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpResponse } from '@angular/common/http'; ...

Prevent selection based on function in Angular

I'm attempting to prevent certain options from being selected based on a specific method. For instance, let's say I have four options: A B C D In my method (let's use "x" as an example): if(name == A) { disable the selection for option A. ...