0

We have a wizard functionality, wherein we have a lazy loaded module having a parent component & 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 basically refers to service, which if no data is there, makes an API call after that we set the Behaviour Subject value in the service & resolve the guard.

HomeGuard

return new Observable(observer=> { 
  this.apiService.getAPIResult().subscribe(res=>{
    this.subjectService.setRequestData(res)  // Inside the subject service, setting the value for the behaviour subject
    observer.next(true)
  });
})

Here 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);
}

Now, we have child route guard i.e ChildGuard . It basically subscribes to the behaviour subject & checks for condition & thereby allow entry to child component.

ChildGuard

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

Now, inside our child route components, whenever user traverse, I am updating the isActive attribute & that is being used inside the guard for checking.

The issue is when the user hits the browser back button, the values are not set in the behaviour subject & entry to the child component is not allowed. To try on a solution, Inside the WizardHomeComponent, I am subcribing to requestData observable & trying to modify & set the subject again but that goes into an infinite loop.

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

2 Answers2

0

If you'd like it to fire once, you can try something like this: It only takes the first value emitted.

WizardHomeComponent
this.subjectService.requestData.pipe(
  first(), // Only take the first value emitted
  map(res => this.modificationFunction(res)) /* Code to edit the res */
).subscribe(modifiedData =>
  this.subjectService.setRequestData(modifiedData)
);
Mrk Sef
  • 7,557
  • 1
  • 9
  • 21
0

there is a problem in your structure. I think you should have a parameter in your URL and get the data from backend and set the requestData in a service. not in a component.

but with a simple null checking (or whatever checking!) your problem will be solved.

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

checkValidation(res){
//check if res is in modifiedData shape
}
behruz
  • 570
  • 4
  • 13