Angular - Routing and refreshing

5,685 views
Skip to first unread message

Chris Anderson

unread,
Feb 25, 2018, 1:00:53 AM2/25/18
to Angular and AngularJS discussion

I'm working on rebuilding an old website from a PHP-based MVC structure platform to Angular. One of the areas where I'm currently running into a problem with is what seems like some basic routing. I've got some paged which are largely static HTML. It seems like overkill to create a component for each one, so I created one component DefaultComponent (the main bulk of the HTML is what I'm displaying as the default when the user hits the url root of the site). In the route module, I created the following route:
{ path: 'site/:view', component: DefaultComponent }

I'm creating the links using routerLink and look like /site/FAQ, /site/about, and /site/disclaimer, and are listed in my navigation are just fine.
The html file then has the HTML content for all four (FAQ, about, disclaimer, and default) outputs and I use ngIf to control which one is visible.

In the ngOnInit routine, I extract the view parameter and use a switch to set a flag that then controls which view should be shown. It works the first time I click one of the links (say the FAQ link). On subsequent clicks though, I see the URL change but the content never changes. 

I feel like I'm missing something simple and basic here. I thought about just creating components for each one, creating static routes for each one and calling it a night, but that feels like cheating, and it seems like this should work. I think what I'm missing is something in the lifecycle events, as the ngOnInit happens when the controller initializes, which happens once... which I get. So what do I need to be looking for when the parameter on the route changes? Like I said, I can see the URL change, but the page doesn't refresh. If I was getting data from the server through a service, I think the example from the Tour of Heroes tutorial would help, but I'm not doing that at this point, it's just static HTML that I'm trying to serve up, so using a service with an observable doesn't make sense - or am I missing something about it?

Thanks in advance.

Sander Elias

unread,
Feb 25, 2018, 4:26:35 AM2/25/18
to Angular and AngularJS discussion
Hi Chris,

Without seeing the code, I would say that you are not subscribing to the router, but only to the static snapshot. The router is providing an observable, that you can subscribe to to update your view.

Regards
Sander

Chris Anderson

unread,
Feb 25, 2018, 11:53:24 AM2/25/18
to Angular and AngularJS discussion
I figured, it was something like that. I eventually found the solution here - https://medium.com/engineering-on-the-incline/reloading-current-route-on-click-angular-5-1a1bfc740ab2 - by subscribing to the NavigationEnd event, I'm able to get the exact results I was looking for.  What I ended up with was this:


  constructor(
   private messageService: MessageService,
   private route: ActivatedRoute,
   private location: Location,
   private router: Router
 ) {

    this.router.events.subscribe((e:any) => {if(e instanceof NavigationEnd) {this.createView();}});
 }

  ngOnInit() {
   this.messageService.add('Default component initialized');
   this.messageService.add('NarrowView: ->' + this.NarrowView);
 }

  createView() {
   this.News = false;
   this.Disclaimer = false;
   this.About = false;
   this.FAQ = false;
   this.NarrowView = true;

    var currentView = this.route.snapshot.paramMap.get('view');
   
   if (currentView != null) { currentView = currentView.toLowerCase();}
   switch (currentView) {
     case 'news': this.News = true; break;
     case 'disclaimer': this.Disclaimer = true; this.NarrowView = false; break;
     case 'about': this.About = true; break;
     case 'faq': this.FAQ = true; this.NarrowView = false; break;
     default: this.News = true; break;
   }

    this.messageService.add('currentView:' + currentView);
   this.messageService.add('NarrowView: ->' + this.NarrowView);
 }




-Chris

Michael Wrock

unread,
Feb 28, 2018, 9:09:44 AM2/28/18
to Angular and AngularJS discussion
Hey Chris,

The issue you're running into here is that when you change routes from /site/about to /site/FAQ the component is not actually going through it's lifecycle because it has not been destroyed. /site/:view matches for both of those URLs and therefore they both map to the same component. In the above example, you are only calling createView() whenever the component is constructed as a result of a NavigationEnd event, but that will only be an appropriate pathway the first time this component is accessed due to how it will be recycled.

What you will want to do, is make a subscription to the route params inside of the ngOnInit lifecycle hook, that will ensure that the subscription is made anytime the component is instantiated, and also will ensure it picks up on any param change.

  // Subscription collection so we can unsubscribe from them on destroy
  private _subscriptions: Subscription[] = [];

  // OnInit Hook, triggered each time the component is instantiated
  public ngOnInit(): void {
    // Add to our subscriptions collection
    this._subscriptions.push(
      // Subscribe to the ActivatedRoute for paramMap changes 
      this._route.paramMap.subscribe((paramMap) => {
        // Retrieve the view named parameter
        const view = paramMap.get('view');
        // Check if we have a defined view
        if (view) {
          // Trigger the view switch
          this.currentView(view);
        }
      })
    );
  }

  // OnDestroy Hook
  private _ngOnDestroy() {
    // Unsubscribe from each Subscription
    this._subscriptions.forEach((subscription: Subscription) => { subscription.unsubscribe() });
  }

The above should help solve your current problem, the only change you will need to make is to allow your createView() method to accept a parameter.

Michael Wrock

unread,
Feb 28, 2018, 9:11:08 AM2/28/18
to Angular and AngularJS discussion
Excuse my typos... 


  // Subscription collection so we can unsubscribe from them on destroy
  private _subscriptions: Subscription[] = [];

  // OnInit Hook, triggered each time the component is instantiated
  public ngOnInit(): void {
    // Add to our subscriptions collection
    this._subscriptions.push(
      // Subscribe to the ActivatedRoute for paramMap changes 
      this.route.paramMap.subscribe((paramMap) => {
        // Retrieve the view named parameter
        const view = paramMap.get('view');
        // Check if we have a defined view
        if (view) {
          // Trigger the view switch
          this.currentView(view);
        }
      })
    );
  }

  // OnDestroy Hook
  public ngOnDestroy() {
Reply all
Reply to author
Forward
0 new messages