11

In my application, there are multiple links in which I have some links with the same route but with different query parameters.

say, I have links like:

.../deposits-withdrawals
.../deposits-withdrawals?id=1
.../deposits-withdrawals?id=2&num=12321344

When I am in one of the above routes and native to the other route from above mentioned, the route is not changing. Not even any of the functions like ngOnInit or ngOnChanges being called.I have changed the parameters from queryParameters to matrixParameters but with no success. I have gone through many links and answers. But, none of them solved my problem. Help me how to solve this.

Thank you...

EDIT:

<button routerLink="/deposits-withdrawals" [queryParams]="{ type: 'deposit' ,'productId': selectedBalance.ProductId}" class="wallet-btns">DEPOSIT {{selectedBalance.ProductSymbol}}</button>
<button routerLink="/deposits-withdrawals" [queryParams]="{ type: 'withdrawal' ,'productId': selectedBalance.ProductId }" class="wallet-btns">WITHDRAW {{selectedBalance.ProductSymbol}}</button>
Sai M.
  • 2,548
  • 4
  • 29
  • 46

4 Answers4

14

I had this problem once. Can you put some code, or solutions you tried? I'll give you something working for me, but you better give me some more details so that I can help. Supposing we are here : some_url/deposits-withdrawals and we wish to navigate , changing only parameters.

    let url = "id=2&num=12321344"
    this.router.navigate(['../', url], { relativeTo: this.route });

Hope it helps :/

=================================== EDIT==================================

You have to detect that query parameters have changed. And for that, you may add a listener to queryParameters changings in the constructor of your component. This can be done using your router this way :

    constructor(route:ActivatedRoute) { 
        route.queryParams.subscribe(val => { 
            // put the code from ngOnInit here 
        }); 
    }

Adding this listener to detect query parameters changes, means you have to move your code from ngOnInit function to this listener. And every time, you navigate, it will be called.

For navigating, you may use html navigation, or ts navigation. If you want it to be in html, you may use :

    <button routerLink="/deposits-withdrawals" [queryParams]="{ type: 'withdrawal' ,'productId': selectedBalance.ProductId }" class="wallet-btns">WITHDRAW {{selectedBalance.ProductSymbol}}</button>
raaaay
  • 496
  • 7
  • 14
AsmaG
  • 487
  • 4
  • 17
  • I have updated the question. Please let me know what are the other things you want to know. I will provide them too. – Sai M. Oct 27 '17 at 08:11
  • okay , Would you try this? https://stackoverflow.com/a/41678403/3428620 ? Tell if it works for you. It should work – AsmaG Oct 27 '17 at 08:26
  • From the above comment, you mean there is no way to do that using query parameters? – Sai M. Oct 27 '17 at 13:57
  • `constructor(route:ActivatedRoute) { route.params.subscribe(val => { // put the code from `ngOnInit` here }); }` means that you will add a listener to the route in case query parameters change. It means you have to navigate first ( using query parameters , in html or in the ts . For example __ . **Then** , you detect these changes in the route listener . – AsmaG Oct 27 '17 at 14:32
  • Thank you. It works in ngOnInit itself. I did something like `this.router.queryParams.subscribe(params => { \\code here });` in ngOnInit as you explained above. This works fine. If you update your answer, I will accept it. – Sai M. Oct 30 '17 at 09:42
  • Done ;) Thank you. Glad it helped – AsmaG Oct 30 '17 at 10:43
  • 1
    @AsmaG Thank you. You are the first easy solution I found. I was wondering how such a simple behaviour requires changing the providers and I just needed to subscribe to the route. – Nico Feb 26 '19 at 16:22
11

The ngOnInit() has to be re-invoked when query parameter is updated. This can be achieved as follow:

import { Router } from '@angular/router';
constructor(private router: Router) {
   this.router.routeReuseStrategy.shouldReuseRoute = () => false;
}
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
Hari Das
  • 10,145
  • 7
  • 62
  • 59
0

Changing parameters usually won't cause an ngOnInit.

If you are navigating to the same page with different parameter, you can listen to events such as NavigationEnd. based on that you will be able to trigger the functions that you want.

    import { Router, NavigationEnd } from '@angular/router';
    export class AppComponent {
    ...
      constructor(public userService: UserService, router:Router) {
        router.events.forEach((event) => {
          if(event instanceof NavigationEnd) {
            console.log(location.pathname);
          }
          //NavigationStart
          // NavigationEnd
          // NavigationCancel
          // NavigationError
          // RoutesRecognized
        });
raaaay
  • 496
  • 7
  • 14
Arman Fatahi
  • 2,635
  • 3
  • 24
  • 37
0

I solved this problem like this.

Suppose you have a container news-list.component.ts with ngOnInit. It saves current queryParams in currentFilters and if there is not them makes simple GET request else it makes POST request.

    ngOnInit() {
      this.route.queryParams.subscribe(queryParams => {
        if (!!queryParams) {
          this.currentFilters = <NewsFilter>{...queryParams, offset: 0, size: 6};
          this.news$ = this.newsPostsService.getNewsByFilter(this.currentFilters);
        } else {
          this.news$ = this.newsPostsService.getMainNews();
        }
      });
    }

Then you create an component <news-rubric></news-rubric> which has following view. You pass there currentFilters and take rubricClick which you process next.

news-list.component.html

    <ml-news-rubrics [currentFilters]="currentFilters"
                     (rubricClicked)="onRubricFilter($event)"
    ></ml-news-rubrics>

news-list.component.ts

    onRubricFilter(filters: NewsFilter) {
      this.currentFilters = {...filters};
      this.router.navigate([], {queryParams: filters, relativeTo: this.route});
    }

And then inside news-rubric.component.ts you do something like this:

    onRubricClicked(rubricId: string) {
      // check if filter exists and if not then put ID in filter
      if (!this.currentFilters.filterByAnyRubricIds) { 
        this.putIdInFilter('filterByAnyRubricIds', rubricId, this.currentFilters.filterByAnyRubricIds);
      } else {
        // check if clicked ID is not in filter. put in filter
        if (!this.currentFilters.filterByAnyRubricIds.includes(rubricId)) { 
          this.putIdInFilter('filterByAnyRubricIds', rubricId, this.currentFilters.filterByAnyRubricIds);
        } else { 
          // if ID in filter remove it from filter
          this.removeIdFromFilter('filterByAnyRubricIds', rubricId, this.currentFilters.filterByAnyRubricIds);
        }
      }
      this.rubricClicked.emit(this.currentFilters);
    }

There is most tricky code. It makes new filter by updating its key with filtered ID.

    private putIdInFilter(key: string, value: any, list: any) {
      if (!list || !(list instanceof Array)) {
        if (!list) {
          this.currentFilters = {...this.currentFilters, [key]: [value]};
        } else {
          this.currentFilters = {...this.currentFilters, [key]: [this.currentFilters[key], value]};
        }
      } else {
        this.currentFilters = {...this.currentFilters, [key]: [...this.currentFilters[key], value]};
      }
    }

    private removeIdFromFilter(key: string, value: any, list: any) {
      if (!list || !(list instanceof Array)) {
        this.currentFilters = <NewsFilter>{
          ...this.currentFilters, [key]: null
        };
        return;
      }
      const filteredValues = [...list.filter(i => i !== value)];
      if (filteredValues.length > 0) {
        this.currentFilters = <NewsFilter>{
          ...this.currentFilters, [key]: filteredValues
        };
      } else {
        delete this.currentFilters[key];
      }
    }

And NewsFilter it is merely interface like QueryParams with keys which are required to be filtered.

raaaay
  • 496
  • 7
  • 14
Alex Po
  • 1,837
  • 1
  • 24
  • 28