简体   繁体   中英

Angular detect route change only when navigating to a different component

I am trying to do something upon route change (ie scroll to top) only when navigating to a different component in my application but not when staying on the same component and just changing its view by a route to the same component with different query params

For example, If I am at /products?category=kitchen and I navigate to /products?category=bedroom I don't want the the operation (ie scroll to top) to perform.

This is the code in my app.component.ts:

this.router.events.pipe(
  filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
  // Would like to check here if user navigates to different component
  if (window) window.scrollTo(0, 0);
});

Does anybody know how I can achieve that?

I want to share how I solved this just in case someone will encounter somthing similar in the future:

private componentBeforeNavigation = null;
  private setScrollToTopOnNavigation() {
    // Scroll to top only when navigating to a different component
    this.router.events.pipe(
      filter(event => event instanceof NavigationEnd)
    ).subscribe((event: NavigationEnd) => {
      let currentRoute = this.route;
      while (currentRoute.firstChild) currentRoute = currentRoute.firstChild;
      if (this.componentBeforeNavigation !== currentRoute.component) {
        if (window) window.scrollTo(0, 0);
      }
      this.componentBeforeNavigation = currentRoute.component;
    });
  }

What this code is doing is using a private property for the component called componentBeforeNavigation which is initially null and every time the Navigation event is fired, the code in the subscribe check if the place I'm navigating now is the same as the last navigation. If yes, it means it is a navigation to the same component and I don't perform my special action (in this case scroll to top of the window) and if no, it means it is a navigation to a new component.
One important thing is to store the new component that I'm navigating to in the property componentBeforeNavigation so it is always updated with the last navigation

You can subscribe to the ActivatedRoute paramMap to do your stuff:

this.activatedRoute.paramMap.subscribe(paramMap  =>  {
        this.router.navigate('your child route here');
    });

and make sure the category view is a child route of products .

Also in place of products view in html template add a routing placeholder where the child view will be placed:

<router-outlet></router-outlet>

You can read more about nested routing here:

EDIT:

Since I don't know your usecase, I can only assume that you are trying to achieve the following:

In your application, somehow, the query parameter "category" can be changed, eg through a click on a category. Instead of doing a

router.navigate(['/products?category=' + newlySelectedCategory]);

and probably reacting on that query parameter with

import {Router, ActivatedRoute, Params} from '@angular/router';
import {OnInit, Component} from '@angular/core';

@Component({...})
export class MyComponent implements OnInit {

  category: string;

  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    // Note: Below 'queryParams' can be replaced with 'params' depending on your requirements
    this.activatedRoute.queryParams.subscribe(params => {
        this.category = params['category'];
    });
  }

}

you can do:

import {Router, ActivatedRoute, Params} from '@angular/router';
import {OnInit, Component} from '@angular/core';

@Component({...})
export class MyComponent implements OnInit {

  category: string;

  constructor(private activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    // Note: Below 'queryParams' can be replaced with 'params' depending on your requirements
    this.activatedRoute.queryParams.subscribe(params => {
        this.category = params['category'];
    });
  }

  // This will probably be called from your html code
  selectCategory(category: string) {
     this.category = category;
     this.location.replaceState(`products?category=${category}`);
  }
}

This way, there will be no routing.


One possible way is to not route, but to change the current URL with this.location.replaceState (assuming you injected private location: Location in your constructor) and manually start the same process that would happen, when you read out the query parameter of the url.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM