2

My requirement is:

  1. After giving the search criteria, show the Search Result below and focus on the search results.
  2. Then after selecting a row from the Search-Result, and OPEN the RECORD in a different page replacing the old one. (Have used router.navigate() method).
  3. From the new page, if user selects BACK hyperlink, user should see the old SEARCH page with the Results.

Now, the problem is, as mentioned above in PointNo 3, I am not able to navigate to the original 'parent page' with all the SEARCH-FORM data and the data; always the initial SEARCH-FORM is coming after navigation (returnToSearchResultsPage() method).

Your headsup and help would be very much appreciated!

-- 1. PARENT PAGE (Search Page):
  showResultsOnSubmit() {
    this.showSearchResults = true; 
  }
=============================================================
-- 2. In results-list-component:
  openRecordDetails(): void {
    this.router.navigate(['individual-details']);
  }

=============================================================

-- 3. CHILD PAGE (In individual-details component):
// Need to return to the search-options page with the search-results intact.
returnToSearchResultsPage() {
    //this.router.navigate(['search-options']);
   // this._location.back();
    window.history.go(-2); 
  }
-- 1. PARENT PAGE (Search Page):
<div>
  <div>
    <h1> Search</h1>
        <form #searchCriteriaForm="ngForm" (ngSubmit)="showResultsOnSubmit()">
          . . .
          <button type="submit"  [disabled]="!searchCriteriaForm.valid">Search</button>
        </form>
  </div>
<!-- ***  Display of the Results Form  @START *** -->
  <div>
    <results-list [showMePartially]="showSearchResults"></results-list>
  </div>
<!-- ****  Display of the Results Form  @END *** -->
</div>



<!-- **  Display of the Results Form  @START *** -->
  <div>
    <results-list [showMePartially]="showSearchResults"></results-list>
  </div>
<!-- ***  Display of the Results Form  @END ** -->


</div>

=============================================================
-- 2. In results-list-component:
        <div>
            <button type="button" (click)="openRecordDetails()">Open Record</button>
     </div>

=============================================================
-- 3. CHILD PAGE (In individual-details component):
<form>

<a href="#" style="margin-left:20px;" *ngIf="isEditModeParent" (click)="returnToSearchResultsPage()"> Return to Search Page</a>
        
. . . .

</form>

4 Answers 4

2

The solution you're looking for is to use the RouteReuseStrategy in the Angular RouterModule when you initially set up your routes. Once implemented you can set a property in your Route configuration to specify which components should be reused, meaning that when you navigate away it won't be destroyed and rebuilt on return.

First create a service that implements the RouteReuseStrategy:

import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router';

export class RouteReuseService implements RouteReuseStrategy {
  private handlers: { [key: string]: DetachedRouteHandle } = {};

  shouldDetach(route: ActivatedRouteSnapshot): boolean {
    if (!route.routeConfig || route.routeConfig.loadChildren) {
      return false;
    }
    let shouldReuse = false;

    if (route.routeConfig.data) {
      route.routeConfig.data.reuse ? shouldReuse = true : shouldReuse = false;
    }

    return shouldReuse;
  }

  store(route: ActivatedRouteSnapshot, handler: DetachedRouteHandle): void {
    if (handler) {
      this.handlers[this.getUrl(route)] = handler;
    }
  }

  shouldAttach(route: ActivatedRouteSnapshot): boolean {
    return !!this.handlers[this.getUrl(route)];
  }

  retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
    if (!route.routeConfig || route.routeConfig.loadChildren) {
      return null;
    }

    return this.handlers[this.getUrl(route)];
  }

  shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean {
    let reUseUrl = false;
    if (future.routeConfig) {
      if (future.routeConfig.data) {
        reUseUrl = future.routeConfig.data.reuse;

      }
    }

    const defaultReuse = (future.routeConfig === current.routeConfig);
    return reUseUrl || defaultReuse;
  }

  getUrl(route: ActivatedRouteSnapshot): string {
    if (route.routeConfig) {
      const url = route.routeConfig.path;
      return url;
    }
  }
}

Update your app.module.ts to add it to the list of providers:

import { RouteReuseStrategy } from '@angular/router';
import { RouteReuseService } from './services/route-reuse.service';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
   ...
  ],
  bootstrap: [...],
  providers: [{
    provide: RouteReuseStrategy,
    useClass: RouteReuseService
  }]
})
export class AppModule {
}

Then to make a component reusable, just add the following to your search route:

data: {
  reuse: true
}

Here's an example:

const routes: Routes = [{
  path: 'search',
  component: SearchComponent,
  data: {
    reuse: true
  }
}, {...}, {...}];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})

After that when you navigate back to your search component it will appear as you'd expect.

Sign up to request clarification or add additional context in comments.

Comments

0

I think the cleanest way to achieve this would be to store the search query somewhere. Be it as a query parameter when navigating, in local storage or in a ngrx-store (which I'd recommend) is totally up to you.

For that you'd have an action that takes the query as a prop which is being watched in a reducer that stores the current query in the store. In your component you can use a selector to select the query from the store. In the component with the search bar you'd have to write something like this:

// formControl is the control bound to the search bar
// store is an ngrx service you have to inject in the constructor
this.formControl.valueChanges.pipe(
    map(query => this.store.dispatch(searchStoreQueryAction({ query }))
)

That dispatches the store action every time you type something in the search bar. You could also dispatch it before navigating or just delay the stream the debounceTime operator.

Ngrx docs: https://ngrx.io/guide/store

Comments

0

You can put your search form data in the state object when you call navigate method, it will be something like that:

  openRecordDetails(): void {
    this.router.navigate(['individual-details'], {state: YOUR_DATA_OBJECT});
  }

And you will have to send the object back when you call returnToSearchResultsPage method from your child page like this:

returnToSearchResultsPage() {
    this.router.navigate(['search-options'], {state: this._location.getState()});
   // this._location.back();
   // window.history.go(-2); 
  }

Then the last part is to add an init method in your parent page where you will get the search form data from your state object :

setSearchFormDataFromPreviousPage(): void {
    if (this.location.getState()) {
        //your code to set your search form data
    }
 }

Comments

0

When the user does a search you need to put the search parameters in the URL. For example:

http://your-domain/search-options // this should be the url when you land on the search page
http://your-domain/search-options?q=elephants // the should be the url after you do a search

Angular has various ways of changing the URL dynamically. I can't remember the methods off the top of my head but you should be able to look them up no problem.

Then when you click BACK you should go to the 2nd URL, not the 1st one.

Now, when the search page loads you should read the parameters in the URL using ActivatedRoute and then do a search using the parameters in the URL inside ngOnInit - or just load as normal if no params in URL.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.