#Triggering Navigation in an Effect

17 messages · Page 1 of 1 (latest)

plain frost
#

I need to create an (invisible) landing page that just gets some data from the URL query parameters and then shoves that into the Route state when navigating to a new view. My linter is complaining about using an async method with effect, but it does work. Any suggestions for how to do this in a better way?

export class ActionsComponent {
  public readonly continueUrl = input<string>();
  public readonly lang = input<string>();
  public readonly mode = input<string>();
  public readonly oobCode = input<string>();

  private readonly _actionState: Signal<Partial<ActionCodeState>>;
  private readonly _modePaths: Record<string, string>;
  private readonly _router: Router;

  constructor() {
    this._actionState = computed(() => ({
      continueUrl: this.continueUrl(),
      lang: this.lang(),
      mode: this.mode(),
      oobCode: this.oobCode(),
    }));
    this._modePaths = {
      recoverEmail: '/recover-email',
      resetPassword: '/reset-password',
      verifyEmail: '/verify-email',
    };
    this._router = inject(Router);

    // eslint-disable-next-line @typescript-eslint/no-misused-promises -- This works, for now, but perhaps not in the future!
    effect(async (): Promise<void> => {
      const state = this._actionState();

      if (state.mode && state.oobCode) {
        const path = this._modePaths[state.mode];

        if (path) {
          await this._router.navigateByUrl(path, { replaceUrl: true, state });
        } else {
          console.error(`Unknown mode '${state.mode}'`);
        }
      } else {
        if (!state.mode) {
          console.error('Missing ActionCodeSettings#mode');
        }
        if (!state.oobCode) {
          console.error('Missing ActionCodeSettings#oobCode');
        }
      }

      // Something about this action is invalid.
      // Navigate to root to allow default redirectTo Route to decide initial destination.
      await this._router.navigateByUrl('/', { replaceUrl: true });
    });
  }
}
#

Hi all! Been about 2 years since I last used Angular. Happy to see so many changes!

grizzled lodge
#

Hi @plain frost . I was wondering if you were still alive. Glad to see you are 🙂

plain frost
#

Sorry, Lot changed really rapidly and I had been quite busy. Glad to see you are still around @grizzled lodge !

#

I have a feeling the answer to my question is stop worrying about awaiting navigate. Because really, I don't have a plan for what to do if the Angular Router fails to navigate where I told it.

grizzled lodge
#

I was just going to say that. I have never (and have never seen anyone) awaited router.navigate calls.

plain frost
#

If you recall, I live and breathe linters

grizzled lodge
#

I do recall. But I explicitly configure it with an exclusion for navigate().

plain frost
#

That is a good idea!

grizzled lodge
#

That said, I wonder

  • why you have that _actionState computed signal
  • if this code shouldn't be in a guard rather than a component.
plain frost
#

My thinking regarding _actionState was that then the effect will wait for all the other InputSignals to be set before trying to navigate. I did not actually test that that is how this works. Do you think there is a problem with too many Signals?

grizzled lodge
#

An effect never has to wait for signals because signals always have a value, and effects are always executed asynchronously, before the change detection. So reading every signal in the effect function is fine. And if you only read 2 of them, then the effect will only retrigger if one of those 2 signals change. By depending on the computed signal, you tell the effect to re-execute when any of the 4 signals change, even though the effect actually only depends on 2 of them. Of course in this case it probably doesn't matter, but its still unnecessary complexity.
And regarding the guard, you can define a route with a guard and a dummy component that will never be activated because the guard will always return a RedirectCommand or an UrlTree.

plain frost
#

Interesting ideas all around! Thank you!

      '@typescript-eslint/no-floating-promises': [
        'error',
        { 
          allowForKnownSafeCalls: [
            { from: 'package', name: 'navigate', package: '@angular/router' },
            { from: 'package', name: 'navigateByUrl', package: '@angular/router' },
          ], 
        },
      ],
calm kite
#

Hey @plain frost, good to see you again. Hope you're doing well!

plain frost
#

@calm kite Good to see you are still around here also!