3

I have a button on a tab page to reset the app for a user by removing a storage entry:

export class Tab1Page {

  constructor(private router: Router, private storage: Storage, private toastController: ToastController) { }

  async resetSettings() {
    await this.storage.remove('welcomeComplete');

    const toast = await this.toastController.create({
      message: 'Your settings have been reset.',
      duration: 2000
    });
    await toast.present();

    console.log('before');
    this.router.navigateByUrl('/');
    console.log('after');
  }
}

In the brower debugger, I can see that the entry is getting deleted from storage. I am also presented with the toast.

However, for some reason, the navigateByUrl method does not seem to be firing. The above pages sits at the url '/tabs/tab1'. Both console.log() statements are executed and there isn't an error in the console.

I'm pretty new to front end development, so apologies if this is a basic newbie question.


Update

my app-routing.module.ts

import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
import { WelcomeGuard } from './welcome/welcome.guard';

const routes: Routes = [
  { 
    path: '', 
    loadChildren: './tabs/tabs.module#TabsPageModule',
    canActivate: [WelcomeGuard]
  },
  { 
    path: 'welcome', 
    loadChildren: './welcome/welcome.module#WelcomePageModule',
  }
];
@NgModule({
  imports: [
    RouterModule.forRoot(routes, { enableTracing: true, preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule {}

my welcome.guard.ts

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router, CanActivate } from '@angular/router';
import { Observable } from 'rxjs';
import { Storage } from '@ionic/storage';

@Injectable({
  providedIn: 'root'
})
export class WelcomeGuard implements CanActivate  {

  constructor(private router: Router, private storage: Storage) {}

  async canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Promise<boolean> {

    const welcomeComplete = await this.storage.get('welcomeComplete');

    if (!welcomeComplete) {
      this.router.navigateByUrl('/welcome');
    }
    return true;
  }
}

I have changed my resetSettings() to the following:

  async resetSettings() {
    await this.storage.remove('welcomeComplete');

    const toast = await this.toastController.create({
      message: 'Your settings have been reset.',
      duration: 2000
    });

    toast.onDidDismiss().then(() => {
      this.router.navigateByUrl('');
    });

    await toast.present();
  }

Changing resetSettings() didn't fix the issue.

Chris Snow
  • 23,813
  • 35
  • 144
  • 309
  • Could you try wrapping the `this.router.navigateByUrl('/');` in a `setTimeout()`? Like this: `setTimeout(() => { this.router.navigateByUrl('/'); }, 0);` – moritzg Mar 20 '19 at 15:18
  • Thanks, but this didn't work either. – Chris Snow Mar 21 '19 at 10:17
  • 1
    I think the problem exists outside of your code sample. Maybe with the router configuration. `navigateByUrl` returns a promise that resolves to either `true` when successful or `false` when not. Do you know if that promise is resolving? If it is not resolving, then you will probably want to make the router chatty so you can see what is happening. This can be done in the app router by setting `enableTracing` to `true` - https://angular.io/api/router/RouterModule#forroot – nephiw Mar 24 '19 at 21:30
  • 1
    Do you have canActivated / canDeactivate guards on the related pages ? – Martin Paucot Mar 25 '19 at 10:45
  • can you create a stackblitz that exhibits the problem? – Doug S. Mar 25 '19 at 14:53
  • Are you in same route '/' when you try to navigate? If so you need to reload current route. (https://medium.com/engineering-on-the-incline/reloading-current-route-on-click-angular-5-1a1bfc740ab2) – Santhosh S Mar 29 '19 at 07:12

6 Answers6

5

It is problem with your guard, below change in welcome.guard.ts can help

 if (!welcomeComplete) {
   this.router.navigateByUrl('/welcome');
   return false;
 }
 return true;

Reason:

in resetSetting function after you call

toast.onDidDismiss().then(() => {
  this.router.navigateByUrl('');
});

It tries to navigate to url : '' that matches first object in route array that is

...
{ 
path: '', 
loadChildren: './tabs/tabs.module#TabsPageModule',
canActivate: [WelcomeGuard]
}
....

then it executes guard function and then you are returning true in any case, it means page got approaval to navigate to '/' and as you are in /tabs/tab1 which is child path of current route setting, so it does nothing and stays in same page.

bharath muppa
  • 1,070
  • 12
  • 30
  • I have a resembling issue https://stackoverflow.com/questions/69351018/navigatebyurl-returns-false/69351339?noredirect=1#comment122595280_69351339 Can you give me your feedback please ? – infodev Sep 28 '21 at 12:55
2

router.navigatByUrl returns a promise with a boolean, which indicates whether routing was successful. I would recommend to log, whether your routing is successful like this:

this.router.navigateByUrl('/').then(success => console.log(`routing status: ${success}`));

I'm guessing that the result will be false, because of your guard. So if I am right, disable your WelcomeGuard by removing it from your route or returning true.

I guess the problem happens because of routing inside of the guard again, but returning true two lines later.

w0ns88
  • 344
  • 2
  • 9
  • 28
Markus Kollers
  • 3,508
  • 1
  • 13
  • 17
1

Like the others, I would check the route you are trying to navigate to matches your router path configuration:

this.router.navigateByUrl('/');

const routes: Routes = [
    {
        path: '/', component: YourComponent, pathMatch: 'full', data: {
        ...
        }
    },

My default route is usually ' ', as opposed to ' / '.

They cover using router.navigate / router.navigateByUrl pretty well here: How to use router.navigateByUrl and router.navigate in Angular

If you include the rest of your relevant code, we might be able to help more with your specific issue.

Caleb Kent
  • 33
  • 3
1

I hope this helps you

Make sure your services methods return an observable.

storage.service.ts

import { Observable } from 'rxjs';

remove() {

  const obs = Observable.create(observer => {
    observer.next('Hello');

    // Throw an error.
    if (error) {
      observer.error("my error");
    }

  });

  return obs;

}

toastController.service.ts

import { Observable } from 'rxjs';

create() {

  const obs = Observable.create(observer => {
    observer.next('Hello');

    // Throw an error.
    if (error) {
      observer.error("my error");
    }

  });

  return obs;

}

Then consume

import { zip } from 'rxjs';


export class Tab1Page {

  constructor(
    private router: Router, 
    private storage: Storage, 
    private toastController: ToastController
  ) { 
    // this.resetSettings();
  }

  resetSettings() {
    const a = this.storage.remove('welcomeComplete');
    const b = this.toastController.create({
      message: 'Your settings have been reset.',
      duration: 2000
    });

    zip(a, b).subscribe( res => {
       this.router.navigateByUrl('/');
       // or
       this.router.navigate(['/']);
    });

  }
}
George C.
  • 6,574
  • 12
  • 55
  • 80
0

Should you will try with navigate instead of navigateByUrl

this.router.navigate(['/']);

Or

this.router.navigate(['']);

Also you could

toast.onDidDismiss().then(()=> {
  this.router.navigate(['/']);
});

Depending your router.

Juan Lozoya
  • 209
  • 6
  • 13
0

In my case, it was happening because there was a redirection preceding the path resolution.

When accessing /, I was redirecting the user to /login so the login page could be loaded.

However, the path-matching strategy I was using was 'prefix' which means the Angular router would choose the redirection instruction for any route prefixed with /, i.e., all routes.

Changing the path-matching strategy to 'full' instructed the Angular route to redirect to /login only when the full path is /. So, the / gets redirected to /login and the /forgot-password do not get redirected to /login anymore.

  { 
    path: '', 
    redirectTo: 'login', 
    pathMatch: 'prefix' // <---- this should be 'full'
  }, 
  {
    path: 'login',
    loadChildren: () => import('./login').then(m => m.LoginPageModule),
  },
  {
    path: 'forgot-password',
    loadChildren: () => import('./forgot-password').then(m => m.ForgotPasswordPageModule)
  },
Wesley Gonçalves
  • 1,985
  • 2
  • 19
  • 22