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

How to stop a checkbox from being selected in Angular 2

I have a table with checkboxes in each row. The table header contains a Check All checkbox that can toggle all the checkboxes in the table rows. I want to implement a feature where, if the number of checkboxes exceeds a certain limit, an error message is ...

Mastering the art of duplicating an array of objects in TypeScript

I attempted the following strategy: this.strategies = []; this.strategiesCopy = [...this.strategies]; Unfortunately, it appears this method is not effective as it results in duplicates. ...

A guide to activating tag selection within the DevExtreme tag box

I'm currently utilizing devExtereme within my Angular project. My goal is to enable the selection of text within tags in my tagbox component. Here's what I have implemented: <dx-tag-box [dataSource]="sourves" [value]="value&quo ...

Is there a way to receive a comprehensive report in case the deletion process encounters an error?

Currently, I am performing a delete operation with a filter based on 2 fields: const query = await Flow.deleteOne({ _id: flowId, permissions: currentUser!.id, }); After executing the delete operation, I inspect the query object to determine its su ...

What is the best way to conceal a specific list item in an Angular 2 template?

I need help figuring out how to hide a selected list item that has been added to another list. I want the added item to be hidden from view in the original list. <div class="countries-list"> <span class="countries-list__header">{{'G ...

Guide on initializing a Redux toolkit state with an array of objects or local storage using TypeScript

Currently, I am attempting to set an initial state (items) to an array of objects or retrieve the same from localStorage. However, I am encountering the following error. Type 'number' is not assignable to type '{ id: string; price: number; ...

Encountering an issue while trying to utilize Vuex in Vue with TypeScript

I recently utilized npm to install both vue (2.4.2) and vuex (2.3.1). However, when attempting to compile the following code snippet, I encountered the following error: https://i.stack.imgur.com/0ZKgE.png Store.ts import Vue from 'vue'; import ...

NGXS Alert: Unable to resolve parameters for TranslationEditorState: (?)

I'm currently implementing NGXS for state management within my Angular 9 application. I've encountered a specific issue where any attempt at dependency injection in one of the state classes results in an error message stating "Error: Can't r ...

The art of Angular localization: harvesting language elements from ts documents

Is it true that $localize is only available for translation in ts files, but the extraction of strings is currently only implemented for templates? I came across information stating that the extraction of strings from ts files should be possible in Angular ...

The user interface in Angular 7 does not reflect the updated values after subscribing

Upon examining the code provided, it is evident that the UI does not reflect the updated value even though the field is set correctly. I have attempted two different approaches but have not explored the change detection approach as I believe the current c ...

Experience the magic of animated number counting using RxJs

I am working on my Angular application and I want to implement a feature where the records from HTTP get requests are animatedly counted. However, when using RxJs, the response is returned too quickly and I only see the final result immediately. I attemp ...

Navigating through a multidimensional array in Angular 2 / TypeScript, moving both upwards and downwards

[ {id: 1, name: "test 1", children: [ {id: 2, name: "test 1-sub", children: []} ] }] Imagine a scenario where you have a JSON array structured like the example above, with each element potenti ...

Observable subscription does not result in updating the value

One of the challenges I'm currently facing in my Angular application is the synchronization of data from a server. To keep track of when the last synchronization took place, I have implemented a function to retrieve this information: fetchLastSyncDate ...

Issue: Module 'stylelint' not found in Angular Project

I've been attempting to execute this command to validate all of the .scss files (and even tried with .css files) and I keep encountering this error. $ stylelint "apps/**/*.scss" It worked once before but not anymore, even after restarting my compute ...

The PhpStorm code completion feature is not functioning properly when working with TypeScript code that is distributed through NPM

I am facing an issue with two NPM modules, which we will refer to as A and B. Both modules are written in TypeScript and compile into CommonJS Node-like modules. Module B has a dependency on module A, so I have installed it using the command npm install ...

Webpack encountering issues with loading dependencies within dependencies

When I try to run webpack, it seems that the compiler is having trouble loading my app.module from within main.ts. Without using webpack, my application can find all modules correctly, but with Webpack, it's failing. This is my webpack configuration: ...

parsing a TypeScript query

Is there a simpler way to convert a query string into an object while preserving the respective data types? Let me provide some context: I utilize a table from an external service that generates filters as I add them. The challenge arises when I need to en ...

Removing a targeted element from an array in Angular

After receiving a JSON array object in Angular using TypeScript, I am attempting to remove a specified object from it. However, my attempts at deletion have been unsuccessful. addCategorySub(categorySub: CategorySubModel, index: number) { categorySub.id ...

Guide on entering text into an Angular input field with Selenium in Python after navigating tabs

After switching tabs, I am attempting to enter text into an Angular input field. However, I keep encountering the following errors: AttributeError: 'tuple' object has no attribute 'send_keys' or ElementClickInterceptedException or NoS ...

Ways to retrieve "this" while utilizing a service for handling HTTP response errors

I have a basic notification system in place: @Injectable({ providedIn: 'root', }) export class NotificationService { constructor(private snackBar: MatSnackBar) {} public showNotification(message: string, style: string = 'success' ...