By constantly subscribing to a Behavior Subject, updating the data, and then resetting the value, an endless loop is created

We have implemented a wizard functionality with lazy loading, consisting of a parent component and multiple child components.

const routes: Routes = [
  {
    path : '',
    component :  WizardHomeComponent,
    canActivate: [HomeGuard],
    children : [
      {
        path : 'route1',
        component :  C1Component,
        canActivate: [ChildGuard]
      },
      {
        path : 'route2',
        component :  C2Component,
        canActivate: [ChildGuard]
      },
      {
        path : 'route3',
        component :  C3Component,
        canActivate: [ChildGuard]
      }
      {
        path : 'complete',
        component :  CompleteFlowComponent,
        canActivate: [ChildGuard]
      }
    ]
  }
];

The HomeGuard utilizes a service that makes an API call if no data is present. The value is then set in the service's Behaviour Subject to resolve the guard.

HomeGuard

return new Observable(observer=> { 
  this.apiService.getAPIResult().subscribe(res=>{
    this.subjectService.setRequestData(res)  
    observer.next(true)
  });
})

Below is the code for the subject service:

Subject Service 

private requestDataSource : BehaviorSubject<IWizard[]> = new BehaviorSubject<IWizard[]>(null);
public _requestData: Observable<IWizard[]> = this.requestDataSource.asObservable();

get requestData() {
  return this._requestData;
}

setRequestData(state) {
  this.requestDataSource.next(state);
}

Furthermore, there is a child route guard called ChildGuard. This guard subscribes to the behaviour subject, checks for conditions, and allows entry to the child component based on the result.

ChildGuard

return this.subjectService.requestData
  .pipe(
    tap(wizard => {
      activeStep = wizard.filter(x=>x.isActive == true);
      /* Additional logic for conditions */
    })
  )
  .pipe(
    map(wizard => isAllowed)
  )

Within the child route components, the isActive attribute is updated as users navigate. However, an issue arises when users hit the browser back button, as the values are not set in the behavior subject prior to entry into the child component.

An attempted solution involves subscribing to the requestData observable within the WizardHomeComponent, modifying the data, and setting the subject again. However, this results in an infinite loop.

WizardHomeComponent
this.subjectService.requestData.subscribe(res=>{
    /* Code to edit the res */
    const modifiedData = this.modificationFunction(res);
    this.subjectService.setRequestData(modifiedData)
});

Answer №1

If you want the event to trigger only once, you can use the following code snippet: It will capture the first emitted value.

WizardHomeComponent
this.subjectService.requestData.pipe(
  first(), // Capture only the first emitted value
  map(res => this.modificationFunction(res)) /* Add your modifications here */
).subscribe(modifiedData =>
  this.subjectService.setRequestData(modifiedData)
);

Answer №2

Your current structure seems to be causing an issue. Consider adding a parameter to your URL and fetching data from the backend to set the requestData in a service rather than in a component.

By implementing a simple null check (or any other form of validation), you should be able to resolve the problem at hand.

this.subjectService.requestData.subscribe(res=>{
    if(!this.checkValidation(res)) {
        /* Add code to manipulate res */
        const modifiedData = this.modificationFunction(res);
        this.subjectService.setRequestData(modifiedData)
    }
});

checkValidation(res){
// Check if res has the expected shape
}

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

Combining the output of two Observables through the CombineLatest method to generate a

I possess two separate collections of information: Data Model: taxControlReference [ { "providerId": "HE", "taxTables": { "STAT": [ 1 ] } }, ...

Using TypeScript to type styled-system props

Currently, I am utilizing styled-system and one of the main features of this library is its shorthand props that allow for simple and quick theming. Although I have streamlined my component, a significant aspect lies here: import React from 'react&a ...

Creating an Angular component that is flexible in terms of the data type it accepts

Currently, I have successfully implemented a lookup component that is responsible for fetching and filtering a list of users based on the query provided. When a user is selected from this list, they are set as members. This component can be configured with ...

Is it possible to apply filters to individual columns in a dynamic mat table using Angular?

Does anyone know how to add a filter for each dynamic column in an Angular Material table? I've only found solutions for static headers, but my table headers are constantly changing. I'm looking for something similar to this example: https://i.st ...

What exactly happens behind the scenes when an API request is cancelled in an ASP .NET Core API?

Let's consider a scenario where we have a straightforward endpoint: [HttpGet] public async Task<ActionResult<string>> Get(CancellationToken cancellationToken) { // some logic here... } Now, imagine I make an HTTP request usi ...

Error message: "Property 'item' is not found within type 'P' - The property is inaccessible in the higher order component even though it is included in the props."

I am currently learning about typescript and exploring how to use Higher Order Components (HoCs) with React in a specific scenario. In my case, I am trying to wrap a component with an HoC that checks whether the "item" passed into the "wrapped" component ...

What could be causing the excessive number of connections in my MongoDB instance?

This code snippet is crucial for my initial connection setup let cachedDbConnection: Db export async function establishDatabaseConnection(): Promise<{ db: Db }> { if (cachedDbConnection) { return { db: cachedDbConnection } } const client ...

The mat-table's data source is failing to refresh and display the latest

When I click on a column header to sort the table, a function should trigger and update the data. However, the data is not updating as expected. Below is the code for the function and the table: <table mat-table #table [dataSource]="dataSourceMD&qu ...

Attempting to implement a typeguard in Typescript that relies on the presence of specific content within an element

Currently, I am attempting to develop a Typescript conditional that verifies if a particular word is already present in the name. The function in question is as follows: isOrganic() { for (let i = 0; i < this.items.length; i++) { if(this.ite ...

I am currently facing an issue related to the length property. It is showing an ERROR TypeError: Cannot read property 'length' of undefined

Is it recommended to set the length to be inherited from Angular right? If so, why am I getting this error: "MyPostsComponent.html: 7 ERROR TypeError: Cannot read the 'length' of undefined property" when fileList.length is greater than 0? onFile ...

Assessing functionality in Angular8 by testing a function that accesses an array from a service

I have a function that I want to test along with the current test setup: canShowIt() { let showit = false; const profils = this.requestsService.userProfil; showit = profils.some((profil) => profil.id === this.profileDetail.id); return showit; ...

Ways to dynamically manipulate HTML elements in Angular 5

Recently, I've been attempting to programmatically transform an HTML element. Strangely, when I update the transform value in the console tab, it changes successfully, but for some reason it doesn't reflect in the element tab of the browser. onD ...

Adding types to computed properties in Vue 3's Composition API is a seamless process

Having an issue where I am trying to add type to computed but keep encountering this error: Overload 1 of 2, '(getter: ComputedGetter<AuthFormType>, debugOptions?: DebuggerOptions | undefined): ComputedRef<AuthFormType>', gave the fol ...

The element does not have a property named "emit" in its type

Trying to transfer data between components using Subject through services resulted in the error message below: 'Property 'emit' does not exist on type 'Subject(any)'. This is what was attempted: component.ts file import { Compo ...

The input field in iOS is shielded by the keyboard on Ionic 5

For months now, I've been struggling with the same issue and I just can't seem to find a solution. The problem arises in an application where there are multiple forms; when a user focuses on an input field, the keyboard covers it up completely ma ...

Angular component fails to render when passed as a string in the innerHtml attribute

One interesting challenge I faced is working with an API that returns HTML containing Angular components which are not being displayed in the application. I am trying to figure out how to display an Angular component stored as a string within the HTML con ...

The vertical scrolling functionality of the MUI DataGrid in Safari may occasionally fail to work

Utilizing the <Box> component from MUI core and the <DataGrid> component from MUIX, along with some other components, I have created a data grid that has the following appearance: https://i.sstatic.net/Gc8sP.png When the number of rows exceed ...

Can you provide information on the latest stable release of animations for Angular 4?

Encountering an error during npm install Warning - @angular/[email protected] requires a peer of @angular/[email protected] but none was installed. Error encountered during npm start Issue with node_modules/@angular/platform-browser/animations ...

Issues with Angular2 causing function to not run as expected

After clicking a button to trigger createPlaylist(), the function fails to execute asd(). I attempted combining everything into one function, but still encountered the same issue. The console.log(resp) statement never logs anything. What could be causing ...

When a variable is used in Postgresql, the ORDER BY clause is disregarded, but accurate results are returned when the variable value is

After investigating, it seems that the query is always returning rows ordered by id, regardless of the value passed in the sortType variable (verified in console). export async function fetchAnimalList(sortType) { noStore(); try { const areas = aw ...