Search code examples
angularangular-reactive-formsresolver

How do I re-run resolvers in Angular with runGuardsAndResolvers and onSameUrlNavigation


I have and edit form and am using resolvers to pre-fetch the data to fill the form. I want to re-use the resolver when the end user clicks the browser refresh button. Currently, the data is not re-called. I believe that is because the data is called within ngOnInit.

I implemented runGuardsAndResolvers: 'always' and onSameUrlNavigation: 'reload'in my route module. This is not working.

I tried calling this.ngOnInit from the constructor. I tried putting the form initialization code in its own private function and calling that from both ngOnInit and within the constructor. This seemed to work, but it appears that I would have to put all of my current ngOnInit code in the private method. I am not sure if that is the best way to go or not.

// Route code
     {
        path: ':id/details/:detailsId/edit', component: TimecardDetailsEditComponent,
        resolve: {
          resolvedTimecard: TimecardSingleResolver,
          resolvedTimecardDetailsSingle: TimecardDetailsSingleResolver
        },
        runGuardsAndResolvers: 'always'
      }
// import
RouterModule.forRoot( appRoutes, { preloadingStrategy: PreloadAllModules, enableTracing: false, onSameUrlNavigation: 'reload' } )
// within ngOnInit
this._route.data.subscribe( data => {
      const resolvedTimecardData: ITimecard = data[ 'resolvedTimecard' ];
      const resolvedTimecardDetailsData: ITimecardDetails = data[ 'resolvedTimecardDetailsSingle' ];
      // Methods set properties with data retrieved
      this.onTimecardRetrieved( resolvedTimecardData );
      this.onTimecardDetailsRetrieved( resolvedTimecardDetailsData );
    } );
// Within the ngOnInit I crete the reactive form and I have a method where I can patch the values returned from the resolved data...It is this patched method I am thinking also needs to be pulled out of ngOnInit

I simply want the resolvers to run when the end user clicks the browser refresh button.

Solution

  • I believe I figured it out. I could not get the resolvers to re-run with clicking the browser refresh button

    In my constructor, I put the following code...

        // I subscribed to the router events and stored the subscription so I can unsubscribe later.
        // I am watching for the navigation end event.
        this.navigationSubscription = this._router.events.subscribe( ( e: any ) => {
          // If the router event is NavigationEnd, I re-initalise the component due to resolvers not running
          if ( e instanceof NavigationEnd ) {
            // Method that makes necessary API calls
            this.initialiseTimecardData();
          }
        } );
    

    I built the initialiseTimecardData method to re-fetch the data.

    initialiseTimecardData () {
        // Set default values and fetch data.
        // Pull parameters from url
        this.timecardId = this._route.snapshot.paramMap.get( 'id' );
        this.timecardDetailsId = this._route.snapshot.paramMap.get( 'detailsId' );
        // NMake the API call that would normally be done in the resolver
        const timecard = this._timecardDetailsSingleService.getTimecardDetails( this.timecardId );
        // Grab necessary employee data as an observable
        this._userProfile$.getEmployeeInfo()
          .subscribe(
            ( datagetEmployeeInfo: IEmployeeInfo ) => {
              this.employeeInfo = datagetEmployeeInfo;
              // Employee exists...create reactive form
              this.createTimecardDetailsForm();
              let timecardDetails: ITimecardDetails;
              timecard.subscribe(
                ( data: ITimecardDetails ) => {
                  for ( const i in data ) {
                    if ( data[ i ].id === +this.timecardDetailsId ) {
                      timecardDetails = data[ i ];
                      // I now have the necessary details. I call methods to populate view
                      this.onTimecardDetailsRetrieved( timecardDetails );
                      this.patchTimecardDetailsForm( this.timecardDetails );
                    }
                  }
                },
                ( err: any ) => console.log( err )
              );
            } );
      }
    

    I also am implementing OnDestroy because I do not want this method to be called on every navigation end, but only this page. This should prevent memory leaks

    ngOnDestroy () {
        if ( this.navigationSubscription ) {
          this.navigationSubscription.unsubscribe();
        }
      }
    

    It works, but please let me know if anyone out there sees any issues with how I did this. I would love the feedback.