ChrisGeo
ChrisGeo

Reputation: 3917

Angular2: Routing to the same page and changing query parameters

I have an Angular 2 project where I want to do the following:

Lets say I have a Component which has a datatable that supports paging and sorting. What I want to achieve is that every time the table page/size and sorting changes, to also change the URL Parameters.

However when I access the particular component from the Router I also want to set the default URL parameters on the Address Bar So the sequence I thought of was the following:

  1. Navigate to my component with no parameters
  2. Set up the query parameters Observable on NgOnInit and upon receiving the first parameters reload the url again to set the default ones
  3. Every time a parameter changes navigate to current route. This will change the params so the query parameter Observable will emit the event. Then a new Ajax call will be triggered.

Now this probably isnt the best idea but the problems I have are the following: 1. The first time two Ajax calls are triggered 2. If I click on the "current route" link on the page NgOnInit doesn't trigger so I cannot replace in the address bar the default parameters.

A short version of the code is the following (I have purposely omitted imports/@Component annotation etc):

export class MyComponent implements OnInit, OnDestroy {

  private params = {page: 0, size: 5}
  private activatedRoute: ActivatedRoute;
  private router: Router;
  private data = []

  private pageLoaded = false;
  private queryParamsSubscription = new Subscription();

  constructor(
    private router: Router, 
    private activatedRoute: ActivatedRoute
    private http: Http) {}

    ngOnInit(): void {
      this.queryParamsSubscription = this.activatedRoute.queryParams
        .debounceTime(100)
        .switchMap((routeParams) => {
          //assign the Url Parameters to my params object
          this.params = Object.keys(routeParams)
            .reduce((params, key) => {
              params[key] = routeParams[key];
              return params
            }, this.params);
          if(!this.pageLoaded) {
            //if the page is not leaded yet run reloadRoute and only replace 
            //the url (true flag) without adding to browser history
            //this will only run once
            this.reloadRoute(true);
            this.pageLoaded = true;
          }
          //finally perform the ajax call with the new params
          //so basically whenever the url parameters change
          //then fire an ajax call
          return this.findAll(this.params)
        })
        .subscribe((data) => {
            this.data = data;
          }
        );
  }

  //request data from the server
  findAll(params: any) {
    let urlParams: : URLSearchParams = //create urlParams from param
    return this.http.get(this.baseUrl, new RequestOptions({search: urlParams}))
     .map((res: Response) => res.json())
     .catch(err => {
       console.error(err);
       return Observable.from(err);
     })
  }

  ngOnDestroy(): void {
    this.queryParamsSubscription.unsubscribe();
  }

  onChangePageSize(size) {
    this.params['size'] = page.size
  }

  onChangePage(page) {
    this.params['page'] = page.page - 1;
    this.reloadRoute();
  }

  //this basically is called every time a parameter changes
  //so I navigate to the same page with the new parameters
  private reloadRoute(replaceUrl: boolean = false) {

    this.router.navigate(
      [this.activatedRoute.routeConfig.path], 
      {queryParams: params, replaceUrl: replaceUrl}
    );
  }

}

Upvotes: 4

Views: 3392

Answers (1)

Lars
Lars

Reputation: 6539

I do something similar, but don't subscribe to the queryParams. Instead I evaluate them from the route-snapshot in the constructor and feed my internal observables with the data, so the view can display whatever the queryParams say.

When the user moves to the "next page", I just feed my observables with the new offset (result view updates automatically) and navigate to the same page with the new queryParams, if they are different from the last queryParams (=> no page reload, no trigger on queryParams, no extra http request).

Upvotes: 3

Related Questions