---
title: Bitovi Academy - Creating Redirect Effects
description: Learn how to create NgRx Effects that redirect the user.
---

- ![AI implementation](https://www.bitovi.com/hubfs/AIConsultingIcon.svg)
  
  [AI implementation](https://www.bitovi.com/services/ai-consulting?hsLang=en-us)
- ![Systems engineering](https://www.bitovi.com/hubfs/icon%20-%20backend.svg)
  
  [Systems engineering](https://www.bitovi.com/services/systems-engineering-consulting?hsLang=en-us)
- ![Project management](https://www.bitovi.com/hubfs/icon%20-%20PM.svg)
  
  [Project management](https://www.bitovi.com/services/agile-project-management-consulting?hsLang=en-us)
- ![Product design](https://www.bitovi.com/hubfs/icon%20-%20design.svg)
  
  [Product design](https://www.bitovi.com/services/product-design-consulting?hsLang=en-us)
- ![Frontend development](https://www.bitovi.com/hubfs/icon%20-%20frontend.svg)
  
  [Frontend development](https://www.bitovi.com/services/frontend-development-consulting?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/digital-consulting-services?hsLang=en-us)

We're Experts in...

- [JavaScript](https://www.bitovi.com/services/frontend/javascript-consulting?hsLang=en-us)
- [AI training](https://www.bitovi.com/ai-training-for-software-engineers?hsLang=en-us)
- [Angular](https://www.bitovi.com/services/frontend/angular-consulting?hsLang=en-us)
- [Design Systems](https://www.bitovi.com/services/axure-figma-migration?hsLang=en-us)
- [React](https://www.bitovi.com/services/frontend/react-consulting?hsLang=en-us)
- [Temporal](https://www.bitovi.com/services/backend/temporal-consulting?hsLang=en-us)
- [React Native](https://www.bitovi.com/services/frontend/react-consulting/react-native?hsLang=en-us)
- [Node.js](https://www.bitovi.com/services/backend/nodejs-consulting-1?hsLang=en-us)

Showcase

![Yum! Brands](https://www.bitovi.com/hubfs/yum-showcase-link-1.png)

[View case study](https://www.bitovi.com/en/bitovi-yum-case-study?hsLang=en-us)

More Projects

- [![Levi's](https://www.bitovi.com/hubfs/levis.svg)](https://www.bitovi.com/web-application-consulting-work/levis-ecommerce-responsive-redesign?hsLang=en-us)
- [![Christie's International Real Estate](https://www.bitovi.com/hubfs/christies.svg)](https://design.bitovi.com/christies)
- [![BAFS](https://www.bitovi.com/hubfs/bafs.svg)](https://www.bitovi.com/ux-design-consulting/ux-case-studies/bafs-ppp?hsLang=en-us)
- [View more
  
  →
  
  ](https://www.bitovi.com/our-software-consulting-work?hsLang=en-us)

Open Source Tools

We build powerful tools and open source them to support the community.

[See what we've built →](https://www.bitovi.com/open-source?hsLang=en-us)

- [![Blog](https://www.bitovi.com/hubfs/icon%20-%20blog.svg)
  
  BlogWe post about perfecting software delivery
  
  ](https://bitovi.com/blog)
- [![Partnerships](https://www.bitovi.com/hubfs/Handshake-1.svg)
  
  PartnershipsLearn about Bitovi's technology partners
  
  ](https://www.bitovi.com/partnerships?hsLang=en-us)
- [![Academy](https://www.bitovi.com/hubfs/limbo/icons/icon-academy.svg)
  
  AcademyFree courses to build delivery skills
  
  ](https://www.bitovi.com/academy/?hsLang=en-us)
- [![Open source tools](https://www.bitovi.com/hubfs/icon%20-%20open%20source.svg)
  
  Open source toolsUse our tools or contribute to our open source mission.
  
  ](https://www.bitovi.com/open-source?hsLang=en-us)

Let's Connect

- [![Discord](https://www.bitovi.com/hubfs/DiscordLogo.svg)
  
  Discord
  
  ](https://discord.gg/J7ejFsZnJ4)
- [![LinkedIn](https://www.bitovi.com/hubfs/LinkedinLogo.svg)
  
  LinkedIn
  
  ](https://www.linkedin.com/company/bitovi/)
- [![GitHub](https://www.bitovi.com/hubfs/GithubLogo.svg)
  
  GitHub
  
  ](https://github.com/bitovi/)

![Eggbot](https://www.bitovi.com/hubfs/build_assets/bitovi-limbo-cms-react/338/js_client_assets/assets/eggbot-LTGhdSGL.png)

Name *

Work Email *

Phone

What's your project?

Send

### Contact Us

(312) 620-0386contact@bitovi.com

- [ Advanced JavaScript ](https://www.bitovi.com/academy/learn-advanced-javascript.html?hsLang=en-us)
- [ DOM and jQuery ](https://www.bitovi.com/academy/learn-dom-jquery.html?hsLang=en-us)
- [ Debug JavaScript ](https://www.bitovi.com/academy/learn-to-debug-javascript.html?hsLang=en-us)
- [ Learn TypeScript ](https://www.bitovi.com/academy/learn-typescript.html?hsLang=en-us)
- [ Learn React Native ](https://www.bitovi.com/academy/learn-react-native.html?hsLang=en-us)
- [ Learn Web Components ](https://www.bitovi.com/academy/learn-web-components.html?hsLang=en-us)
- [ Agile Program Management With Jira ](https://www.bitovi.com/academy/learn-agile-program-management-with-jira.html?hsLang=en-us)
- [ Learn RxJS ](https://www.bitovi.com/academy/learn-rxjs.html?hsLang=en-us)
- [ Giving a Training ](https://www.bitovi.com/academy/training.html?hsLang=en-us)
- [ Learn Technology Consulting ](https://www.bitovi.com/academy/learn-technology-consulting.html?hsLang=en-us)
- [ Learn React ](https://www.bitovi.com/academy/learn-react.html?hsLang=en-us)
- [ Learn NgRx ](https://www.bitovi.com/academy/learn-ngrx.html?hsLang=en-us) 
    - [ Why NgRx ](https://www.bitovi.com/academy/learn-ngrx/why-ngrx.html?hsLang=en-us)
    - [ Getting Started ](https://www.bitovi.com/academy/learn-ngrx/getting-started.html?hsLang=en-us)
    - [ Installing NgRx ](https://www.bitovi.com/academy/learn-ngrx/ngrx-init.html?hsLang=en-us)
    - [ Creating Actions ](https://www.bitovi.com/academy/learn-ngrx/create-actions.html?hsLang=en-us)
    - [ Dispatching Actions ](https://www.bitovi.com/academy/learn-ngrx/dispatch-actions.html?hsLang=en-us)
    - [ Testing Actions ](https://www.bitovi.com/academy/learn-ngrx/test-actions.html?hsLang=en-us)
    - [ Create an API Effect ](https://www.bitovi.com/academy/learn-ngrx/create-api-effects.html?hsLang=en-us)
    - [ Testing API Effects ](https://www.bitovi.com/academy/learn-ngrx/test-api-effects.html?hsLang=en-us)
    - [ Creating Redirect Effects ](https://www.bitovi.com/academy/learn-ngrx/create-redirect-effects.html?hsLang=en-us)
    - [ Testing Redirect Effects ](https://www.bitovi.com/academy/learn-ngrx/test-redirect-effects.html?hsLang=en-us)
    - [ Create a Reducer ](https://www.bitovi.com/academy/learn-ngrx/create-reducer.html?hsLang=en-us)
    - [ Testing Reducers ](https://www.bitovi.com/academy/learn-ngrx/test-reducer.html?hsLang=en-us)
    - [ Creating Selectors ](https://www.bitovi.com/academy/learn-ngrx/create-selectors.html?hsLang=en-us)
    - [ Testing Selectors ](https://www.bitovi.com/academy/learn-ngrx/test-selectors.html?hsLang=en-us)
    - [ Using Selectors ](https://www.bitovi.com/academy/learn-ngrx/use-selectors.html?hsLang=en-us)
    - [ Testing Selector Use ](https://www.bitovi.com/academy/learn-ngrx/test-used-selectors.html?hsLang=en-us)
- [ Learn Graphql ](https://www.bitovi.com/academy/learn-graphql.html?hsLang=en-us)
- [ Learn Docker ](https://www.bitovi.com/academy/learn-docker.html?hsLang=en-us)
- [ Learn CanJS ](https://www.bitovi.com/academy/learn-canjs.html?hsLang=en-us)
- [ Learn Angular ](https://www.bitovi.com/academy/learn-angular.html?hsLang=en-us)
- [ Advanced TypeScript ](https://www.bitovi.com/academy/advanced-typescript.html?hsLang=en-us)

[View More Courses](https://www.bitovi.com/academy/#courses) [ ]

# Creating Redirect Effects `page`

Learn how to create NgRx Effects that redirect the user.

> **Quick Start**: You can checkout [this branch](https://github.com/bitovi/angular-ngrx-chat/tree/test-api-effects) to get your codebase ready to work on this section.

## Overview

1. Add `loginSuccess$` Effect to `LoginEffects` to navigate to dashboard page.
2. Add `logoutSuccess$` Effect to `LoginEffects` to navigate to login page.

## Problem 1: Create `loginSuccess$` Effect to Handle Navigating to Dashboard Page

`LoginEffects` should use `Router` to navigate to the dashboard page at path `/dashboard` using an Effect called `loginSuccess$`.

## P1: What you need to know

Although it’s common for Effects to dispatch another Action after handling a side-effect, there is a way to update the configuration for an Effect to never dispatch an Action instead. This is useful when a side-effect resolves and there’s no need to trigger another side-effect or update state.

To understand this better, let’s take a deeper dive into the `createEffect()` [helper function](https://ngrx.io/api/effects/createEffect):

`createEffect()` takes two arguments:

1. `source` - A function which returns an `Observable`.
2. `config` (optional) - A `Partial<EffectConfig>` to configure the Effect. By default, `dispatch` option is true and `useEffectsErrorHandler` is true.

And if we look a little deeper, here is the type definition of the `EffectConfig` interface:

```
/**
 * Configures an Effect created by `createEffect()`.
 */
export interface EffectConfig {
  /**
   * Determines if the Action emitted by the Effect is dispatched to the store.
   * If false, Effect does not need to return type `Observable<Action>`.
   */
  dispatch?: boolean;
  /**
   * Determines if the Effect will be resubscribed to if an error occurs in the main Actions stream.
   */
  useEffectsErrorHandler?: boolean;
}
```

By default, the `dispatch` option is set to `true`, but if we set it to `false`, the Effect doesn’t have to end with an Action being dispatched:

```
// Note: This example code is not part of our application repo or solution

import { Injectable } from '@angular/core';
import { Observable, exhaustMap } from 'rxjs/operators';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import * as ContactActions from './contact.actions';

@Injectable()
export class ContactEffects {
  submitSuccess$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(ContactActions.submitSuccess),
      exhaustMap(({ confirmationNumber }) =>
        // call `showModal()`, but doesn’t `map` to some Action
        this.showModal(confirmationNumber)
      )
    );
  }, { dispatch: false });
 
  constructor(private actions$: Actions) {}

  private showModal(confirmationNumber: number): Observable<void> {/* ... */}
}

```

## P1: Solution

src/app/store/login/login.effects.ts

```
// src/app/store/login/login.effects.ts

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { catchError, map, exhaustMap } from 'rxjs/operators';
import { of } from 'rxjs';
import * as LoginActions from './login.actions';
import { LoginService } from 'ngx-learn-ngrx';
import { Router } from '@angular/router';

@Injectable()
export class LoginEffects {
  login$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(LoginActions.login),
      exhaustMap(({ username, password }) =>
        this.loginService.login({ username, password }).pipe(
          map(({ userId, token }) =>
            LoginActions.loginSuccess({ userId, username, token })
          ),
          catchError((error: unknown) =>
            of(
              LoginActions.loginFailure({
                errorMsg: this.getErrorMessage(error),
              })
            )
          )
        )
      )
    );
  });

  loginSuccess$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(LoginActions.loginSuccess),
        exhaustMap(() => this.router.navigate(['dashboard']))
      );
    },
    { dispatch: false }
  );

  logout$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(LoginActions.logout),
      exhaustMap(() =>
        this.loginService.logout().pipe(
          map(() => LoginActions.logoutSuccess()),
          catchError((error: unknown) =>
            of(
              LoginActions.logoutFailure({
                errorMsg: this.getErrorMessage(error),
              })
            )
          )
        )
      )
    );
  });

  constructor(
    private actions$: Actions,
    private loginService: LoginService,
    private router: Router
  ) {}

  private getErrorMessage(error: unknown): string {
    if (error instanceof Error) {
      return error.message;
    }
    return String(error);
  }
}

```

## Problem 2: Create `logoutSuccess$` Effect to Handle Navigating to Login Page

`LoginEffects` should use `Router` to navigate to the dashboard page at path `/` using an Effect called `loginSuccess$`.

## P2: Solution

src/app/store/login/login.effects.ts

```
// src/app/store/login/login.effects.ts

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { catchError, map, exhaustMap } from 'rxjs/operators';
import { of } from 'rxjs';
import * as LoginActions from './login.actions';
import { LoginService } from 'ngx-learn-ngrx';
import { Router } from '@angular/router';

@Injectable()
export class LoginEffects {
  login$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(LoginActions.login),
      exhaustMap(({ username, password }) =>
        this.loginService.login({ username, password }).pipe(
          map(({ userId, token }) =>
            LoginActions.loginSuccess({ userId, username, token })
          ),
          catchError((error: unknown) =>
            of(
              LoginActions.loginFailure({
                errorMsg: this.getErrorMessage(error),
              })
            )
          )
        )
      )
    );
  });

  loginSuccess$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(LoginActions.loginSuccess),
        exhaustMap(() => this.router.navigate(['dashboard']))
      );
    },
    { dispatch: false }
  );

  logout$ = createEffect(() => {
    return this.actions$.pipe(
      ofType(LoginActions.logout),
      exhaustMap(() =>
        this.loginService.logout().pipe(
          map(() => LoginActions.logoutSuccess()),
          catchError((error: unknown) =>
            of(
              LoginActions.logoutFailure({
                errorMsg: this.getErrorMessage(error),
              })
            )
          )
        )
      )
    );
  });

  logoutSuccess$ = createEffect(
    () => {
      return this.actions$.pipe(
        ofType(LoginActions.logoutSuccess),
        exhaustMap(() => this.router.navigate(['']))
      );
    },
    { dispatch: false }
  );

  constructor(
    private actions$: Actions,
    private loginService: LoginService,
    private router: Router
  ) {}

  private getErrorMessage(error: unknown): string {
    if (error instanceof Error) {
      return error.message;
    }
    return String(error);
  }
}

```

## Verify Implementation

At this point, you should be able to login on the login page:

> Note that authenication **DOES NOT** persist after a **page refresh**. This means that after you make code changes while serving the application, you will be signed out and will need to login again. Remember that the login page is located at `/`.

The `LoginService.login()` method will throw an error if any of these cases are not met:

1. `password` must be at least 6 characters.
2. `username` must be at least 3 characters.
3. `username` must be alphanumeric including hyphens or underscores.

*When one of these requirements aren’t met, an error is thrown and an error is logged in the console in red text.*

> **Wrap-up**: By the end of this section, your code should match [this branch](https://github.com/bitovi/angular-ngrx-chat/tree/create-redirect-effects). You can also compare the [code changes for our solution to this section](https://github.com/bitovi/angular-ngrx-chat/compare/test-api-effects...create-redirect-effects) on GitHub or you can use the following command in your terminal:

```
git diff origin/create-redirect-effects
```

###### On this page...

###### Get help

If you need [help](https://discord.gg/J7ejFsZnJ4) with an exercise, please reach out to us on [Discord](https://discord.gg/J7ejFsZnJ4)

If you find a bug, please [create an issue](https://github.com/bitovi/academy/issues/new) or email [contact@bitovi.com](mailto:contact@bitovi.com?Subject=Training%20Suggestion)

## Join the Bitovi Newsletter

 Do you want to receive updates about new Bitovi Academy courses, Bitovi open source projects, and dev community news? If so, please provide your email. We won’t spam you or give it away for any reason!  
*By providing your email you agree to receive communications from Bitovi*

![](https://bitovi.github.io/academy/static/img/close.svg)

```json
{
     "@context": "http://schema.org",
     "@type": "Organization",
     "mainEntityOfPage":{
          "@type":"WebPage",
          "@id":"https://www.bitovi.com/academy/learn-ngrx/create-redirect-effects.html",
          "description": "Learn how to create NgRx Effects that redirect the user. 
"
     },
     "url": "http://bitovi.com",
     "logo": "https://www.bitovi.com/hubfs/bitovi-logo-23-1.svg",
     "image": "https://www.bitovi.com/hubfs/bitovi-logo-x2.png",
     "name": "Bitovi Web App Consulting",
     "alternateName": "Bitovi",
      "naics": "541511",
      "description": "Bitovi is a UX, UI design and front-end JavaScript development consulting company",
     "address": {
          "@type": "PostalAddress",
          "streetAddress": "1134 Pine Tree Lane ",
          "addressLocality": "Libertyville",
          "addressRegion": "IL",
          "addressCountry": "United States",
          "postalCode": "60048"
     },
     "areaServed": {
          "@type": "GeoCircle",
          "geoMidpoint": {
               "@type": "GeoCoordinates",
               "latitude": "41.8781",
               "longitude": "87.6298"
          },
          "geoRadius": "5000 km"
     },
     "telephone": "312-620-0386",
     "email": "contact@bitovi.com",
     "sameAs": [
          "https://www.facebook.com/BitoviLLC/",
          "https://twitter.com/bitovi",
          "https://www.linkedin.com/company/bitovi"
     ]
}
```