Dispatching Actions page

Learn how to dispatch NgRx Actions from within Angular Components.

Quick Start: You can checkout this branch to get your codebase ready to work on this section.

Overview

  1. Update LoginComponent to dispatch LoginActions.login Action.

  2. Update DashboardComponent to dispatch LoginActions.logout Action.

Problem 1: Dispatch Login Action on LoginComponent

Now that we have our Actions, let’s use them. The LoginComponent should have the Login Action be dispatched when the submit button is clicked.

P1: What you need to know

We can import our Action creators from src/app/store/login/login.actions.ts to create Actions and then use the NgRx Store to dispatch them:

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

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import * as ContactActions from '../store/contact/contact.actions';

@Component({
  selector: 'app-contact',
  templateUrl: './contact.component.html',
  styleUrls: ['./contact.component.scss'],
})
export class ContactComponent {
  constructor(private store: Store) {}

  submit(emailAddress: string, fullName: string): void {
    this.store.dispatch(ContactActions.submit({ emailAddress, fullName }));
  }
}

In upcoming sections, we will discuss how dispatched Actions can trigger Reducer functions (Create a Reducer) and how Effects listen to Actions dispatched from the Store to handle side-effects (Create an API Effect). You can learn more about how to write Actions and how to dispatch them in the NgRx documentation on Actions.

In the LoginComponent, there is a TODO where the Login Action should be dispatched.

P1: Solution

src/app/login/login.component.ts

// src/app/login/login.component.ts

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import * as LoginActions from '../store/login/login.actions';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss'],
})
export class LoginComponent {
  protected readonly form = this.fb.nonNullable.group({
    username: ['', [Validators.required]],
    password: ['', [Validators.required]],
  });

  constructor(private fb: FormBuilder, private store: Store) {}

  submit(): void {
    this.form.markAllAsTouched();
    if (this.form.invalid) {
      return;
    }

    this.store.dispatch(
      LoginActions.login({
        username: this.form.controls.username.value,
        password: this.form.controls.password.value,
      })
    );
  }
}

Problem 2: Dispatch Logout Action on DashboardComponent

And the DashboardComponent should have the Logout Action be dispatched when the logout button is clicked.

P2: What you need to know

In the DashboardComponent, there is a TODO where the Logout Action should be dispatched.

P2: Solution

src/app/dashboard/dashboard.component.ts

// src/app/dashboard/dashboard.component.ts

import { Component } from '@angular/core';
import { of } from 'rxjs';
import { Store } from '@ngrx/store';
import * as LoginActions from '../store/login/login.actions';

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss'],
})
export class DashboardComponent {
  // Select username from store
  // TODO: Replace `of('TODO')` with selectUsername selector
  readonly username$ = of('TODO');

  // Select user ID from store
  // TODO: Replace `of('TODO')` with selectUserId selector
  readonly userId$ = of('TODO');

  constructor(private store: Store) {}

  logout(): void {
    this.store.dispatch(LoginActions.logout());
  }
}

Wrap-up: By the end of this section, your code should match this branch. You can also compare the code changes for our solution to this section on GitHub or you can use the following command in your terminal:

git diff origin/dispatch-actions