Part 13 - Router actions and effects

1 .Add a new presentational components for users

ng g c components/users-table -a=admin-portal/users
  • Add a toolbar module
ng g c components/users-table-toolbar -a=admin-portal/users
  • Add a toolbar with select field

libs/admin-portal/users/src/components/users-table-toolbar/users-table-toolbar.component.html

<mat-toolbar>
  <mat-form-field >
    <mat-select [value]="selectedCountry" (selectionChange)="filter($event.value)" >
      <mat-option>None</mat-option>
      <mat-option value="australia" >Australia</mat-option>
      <mat-option value="england">England</mat-option>
      <mat-option value="usa">USA</mat-option>
    </mat-select>
  </mat-form-field>
</mat-toolbar>

libs/admin-portal/users/src/components/users-table-toolbar/users-table-toolbar.component.ts

import { Component, OnInit, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'users-table-toolbar',
  templateUrl: './users-table-toolbar.component.html',
  styleUrls: ['./users-table-toolbar.component.scss']
})
export class UsersTableToolbarComponent {
  @Output() onFilter = new EventEmitter<string>();
  selectedCountry = 'none';

  filter(country:string){
    this.onFilter.emit(country);
  }
}
  • Add a users list table component

libs/admin-portal/users/src/components/users-table/users-table.component.ts

import { Component, OnInit, Input, OnChanges, SimpleChanges } from '@angular/core';
import { User } from '@demo-app/data-models';
import { MatTableDataSource } from '@angular/material';

@Component({
  selector: 'app-users-table',
  templateUrl: './users-table.component.html',
  styleUrls: ['./users-table.component.scss']
})
export class UsersTableComponent implements OnChanges {
  @Input() users: User[];

  displayedColumns = ['username', 'country'];
  dataSource: MatTableDataSource<User>;

  ngOnChanges(changes: SimpleChanges) {
    this.dataSource = new MatTableDataSource(this.users);
  }

  setTableDatasource(dataSource): void {
    this.dataSource = new MatTableDataSource(this.users);
  }

}
  • Add the html

libs/admin-portal/users/src/components/users-table/users-table.component.html

<div class="mat-elevation-z8">
  <mat-table #table [dataSource]="dataSource">

    <ng-container matColumnDef="username">
      <mat-header-cell *matHeaderCellDef> Username </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.username}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="country">
      <mat-header-cell *matHeaderCellDef> Country </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.country}} </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>
</div>

2. Add filter actions to update state

import { Action } from '@ngrx/store';
import { User } from '@demo-app/data-models';

export enum UsersActionTypes {
  LoadUsers = '[Users] Load',
  LoadUsersSuccess = '[Users] Load Sucess',
  LoadUsersFail = '[Users] Load Fail',
  SetUsersFilter = '[Users] Set Filter'
}

export class LoadUsersAction implements Action {
  readonly type = UsersActionTypes.LoadUsers;
}

export class LoadUsersSuccessAction implements Action {
  readonly type = UsersActionTypes.LoadUsersSuccess;
  constructor(public payload: User[]) {}
}

export class LoadUsersFailAction implements Action {
  readonly type = UsersActionTypes.LoadUsersSuccess;
  constructor(public payload: any) {}
}

export class SetUsersFiltersAction {
  readonly type = UsersActionTypes.SetUsersFilter;
  constructor(public payload: string) {}
}

export type UsersActions =
  | LoadUsersAction
  | LoadUsersSuccessAction
  | LoadUsersFailAction
  | SetUsersFiltersAction;
  • Update the users state to have a selectedCountry
import { EntityState } from '@ngrx/entity';
import { User } from '@demo-app/data-models';

export interface Users extends EntityState<User> {
  selectedUserId: number;
  loading: boolean;
  selectedCountry: string
}

export interface UsersState {
  readonly users: Users;
}
  • Update the initial state

libs/admin-portal/users/src/+state/users.interface.ts

import { Users } from './users.interfaces';
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { User } from '@demo-app/data-models';

export const adapter: EntityAdapter<User> = createEntityAdapter<User>({});

export const usersInitialState: Users = adapter.getInitialState({
  selectedUserId: null,
  loading: false,
  selectedCountry: 'none'
});
  • Remove load dispatch aciton from component

libs/admin-portal/users/src/+state/users.init.ts

ngOnInit() {
  // this.store.dispatch(new usersActions.LoadUsersAction());
  this.users$ = this.store.select(selectAllUsers);
}

3. Add router method to user-list component

libs/admin-portal/users/src/containers/user-list/user-list.component.html

<users-table-toolbar (onFilter)="updateUrlFilters($event)"></users-table-toolbar>
<app-users-table [users]="users$ | async"></app-users-table>

libs/admin-portal/users/src/containers/user-list/user-list.component.ts

updateUrlFilters(country: string): void {
  const navigationExtras: NavigationExtras = {
    replaceUrl: true,
    queryParams: {country}
  };
  this.router.navigate([`/users`], navigationExtras);
}
  • Add an effect to listen for the route change
  @Effect()
  loadUsersFromRoute = this.dataPersistence.navigation(UserListComponent, {
    run: (a: ActivatedRouteSnapshot, state: UsersState) => {
      return this.usersService
        .getUsers(a.queryParams['country'])
        .pipe(
          map((users: User[]) => new usersActions.LoadUsersSuccessAction(users))
        );
    },
    onError: (a: ActivatedRouteSnapshot, e: any) => {
      return new usersActions.LoadUsersFailAction(e);
    }
  });
  • Update the user service
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class UsersService {
  constructor(private httpClient: HttpClient) {}

  getUsers(country: string = null) {
    const url = country !== null
      ? `http://localhost:3000/users?country=${country}`
      : `http://localhost:3000/users`;

    return this.httpClient.get(url);
  }
}

results matching ""

    No results matching ""