Optimistic state updates using @nrwl/angular#optimisticUpdate

Overview

NxOptimisticState

Quickstart:

$ npm ci

$ npx nx serve ou-ui

This simple project was created as a PoC to show comparison of two different approaches to handling API calls using NgRx Store and @nrwl/angular.

Sources overview

check these files for more info:

Classic approach

Using loading progress in views triggered by loading flags on FE.

This pattern is relying on 3 types of NgRx Store Actions:

  • Trigger Action (create, update/edit, delete) which triggers API call; e.g. deleteTask
  • Success Action which processes the response from API; e.g. deleteTaskSuccess
  • Failure Action which processes the error response from API; e.g. deleteTaskFailure
Classic success Classic error
image image

Examples

Classic delete

import * as TasksActions from './tasks.actions';

...
  deleteTask$ = createEffect(() =>
    this.actions$.pipe(
      ofType(TasksActions.deleteTask),
      fetch({
        run: ({ id }) =>
          this.fakeAPI
            .deleteTask(id)
            .pipe(map((id) => TasksActions.deleteTaskSuccess({ id }))),
        onError: (action, error) => {
          console.error('Error deleteTask$: ', error);
          this.message.error('Could not delete task');
          return TasksActions.deleteTaskFailure({ error });
        },
      })
    )
  );
Classic success Classic error
delete-classic-scss delete-classic-err

Classic Create task implementation

import * as TasksActions from './tasks.actions';

...
  createTask$ = createEffect(() =>
    this.actions$.pipe(
      ofType(TasksActions.createTask),
      fetch({
        run: (action) =>
          this.fakeAPI
            .createTask(action.name, action.status)
            .pipe(map((task) => TasksActions.createTaskSuccess({ task }))),
        onError: (action, error) => {
          console.error('Error createTask$: ', error);
          this.message.error('Could not create task');
          return TasksActions.createTaskFailure({ error });
        },
      })
    )
  );
Classic success Classic error
clsc-scss clsc-err

Optimistic approach

The Optimistic UI is ideal when the responses from API take longer than desired from UX point of view. This approach assumes a high success rate of received API responses and (in ideal case*) expecting the response from API wouldn't differ from the actual data modified on client.

Most times is relying on 2 types of NgRx Store Actions:

  • Trigger Action (create, update/edit, delete) which triggers API call AND immediately sets the new state containing new data on client (in store); e.g. deleteTaskOptimistic
  • Undo Action which is triggered upon receiving an error from API. Its purpose is to revert the new state to original state before the data modification.
Optimistic success Optimistic error
image image

Examples

Optimistic delete

import * as TasksActions from './tasks.actions';

...
  deleteTaskOptimistic$ = createEffect(() =>
    this.actions$.pipe(
      ofType(TasksActions.deleteTaskOptimistic),
      optimisticUpdate({
        run: ({ task }) =>
          this.fakeAPI.deleteTask(task.id).pipe(switchMap(() => EMPTY)),
        undoAction: ({ task }, error) => {
          console.error('Error deleteTask$: ', error);
          this.message.error('Could not delete task');
          return TasksActions.undoDeleteTask({
            error,
            task,
          });
        },
      })
    )
  );
Optimistic success Optimistic error
delete-opt-scss delete-opt-err

Edge case for optimistic approach

In some cases, just as in optimistic create, there can be a requirement for optimistic approach even though the API response differs in some way from the data modified on client. This use-case can be handled by adding a Success Action which re-maps or adds missing data to our entity.

Optimistic success Optimistic error
image image

Examples

Optimistic Create task implementation

In this case we don't know what ID will be generated on BE, so we need to generate our own on client and replace it in Success Action

import { optimisticUpdate } from '@nrwl/angular';

import * as TasksActions from './tasks.actions';

...
  createTaskOptimistic$ = createEffect(() =>
    this.actions$.pipe(
      ofType(TasksActions.createTaskOptimistic),
      optimisticUpdate({
        run: (action) =>
          this.api.createTask(action.task.name, action.task.status).pipe(
            tap(() => this.message.success('Task created')),
            // needs another action for replacing Optimistic ID (oid)
            map((task) =>
              TasksActions.createTaskOptimisticSuccess({
                oid: action.task.id,
                task,
              })
            )
          ),
        undoAction: (action, error) => {
          // add error handling here
          console.error('Error createTask$');
          // call Undo Action
          return TasksActions.undoCreateTask({
            error,
            /**
            * notice the the Undo Action's payload - in this case ID is enough, 
            * we're just removing it from the TasksEntities
            **/
            id: action.task.id, 
          });
        },
      })
    )
  );
Optimistic success Optimistic error
optmstc-scss optmstc-err
You might also like...

Component infrastructure and Material Design components for Angular

Official components for Angular The Angular team builds and maintains both common UI components and tools to help you build your own custom components

Jan 3, 2023

Angular UI Component Library based on Ant Design

Angular UI Component Library based on Ant Design

NG-ZORRO An enterprise-class Angular UI component library based on Ant Design. English | 简体中文 ✨ Features An enterprise-class UI design system for Angu

Jan 6, 2023

Angular 2 building blocks :package: based on Semantic UI

Angular 2 building blocks :package: based on Semantic UI

Angular2 & Semantic UI Angular2 - Semantic UI Live demo ng-semantic.herokuapp.com Angular 2 Semantic UI version: 2.2.2 Installation npm install ng-sem

Dec 23, 2022

Native Angular components & directives for Lightning Design System

ng-lightning This library contains native Angular components and directives written from scratch in TypeScript using the Lightning Design System CSS f

Dec 8, 2022

Native AngularJS (Angular) directives for Bootstrap

Native AngularJS (Angular) directives for Bootstrap. Smaller footprint (20kB gzipped), no 3rd party JS dependencies (jQuery, bootstrap JS) required. Please read the README.md file before submitting an issue!

Jan 3, 2023

NG Bootstrap - Angular powered Bootstrap widgets

NG Bootstrap - Angular powered Bootstrap widgets Angular widgets built from the ground up using only Bootstrap 4 CSS with APIs designed for the Angula

Dec 24, 2022

🚀 Style and Component Library for Angular

ngx-ui Component & Style Library for Angular by Swimlane. Installing npm i @swimlane/ngx-ui --S Install the project's peer depencencies (moment, codem

Dec 24, 2022

Lightweight, Material Design inspired go to top button. No dependencies. Pure Angular!

Lightweight, Material Design inspired go to top button. No dependencies. Pure Angular!

Angular ScrollTop Button Lightweight, Material Design inspired button for scroll-to-top of the page. No dependencies. Pure Angular! ✓ Angular 13, Ivy

Dec 18, 2022

The best way to quickly integrate Bootstrap 5 Bootstrap 4 or Bootstrap 3 Components with Angular

 The best way to quickly integrate Bootstrap 5 Bootstrap 4 or Bootstrap 3 Components with Angular

ngx-bootstrap The best way to quickly integrate Bootstrap 5 Bootstrap 4 or Bootstrap 3 Components with Angular Links Documentation Release Notes Slack

Jan 8, 2023
Owner
Marek Pakes
Marek Pakes
Sam4Sc - a migration assistant for Angular to SCAM (Single Angular Component Modules) and Standalone Components

Sam4Sc - a migration assistant for Angular to SCAM (Single Angular Component Modules) and Standalone Components

Rainer Hahnekamp 7 Nov 16, 2022
Clarity Angular is a scalable, accessible, customizable, open-source design system built for Angular.

Getting Started Clarity Angular is published as two npm packages: Contains the static styles for building HTML components. Contains the Angular compon

VMware Clarity 145 Dec 29, 2022
An example application that uses file-based routing with Angular, Analog, Vite with the Angular Router

Angular, Vite, and File-based routes This is an example application that uses Angular, Analog, and Vite for file-based routing. Routes are places in t

Brandon 9 Sep 25, 2022
Monorepo for all the tooling related to using ESLint with Angular

Angular ESLint Monorepo for all the tooling which enables ESLint to lint Angular projects

angular-eslint 1.4k Dec 29, 2022
Food Card website using angular Feature: add to cart remove to cart searching food filter food

SearchBar This project was generated with Angular CLI version 13.1.2. Development server Run ng serve for a dev server. Navigate to http://localhost:4

Gaurav Gupta 1 Jan 20, 2022
A tower defense game using Angular 13 + Phaser 3

PortalsTd This project was generated with Angular CLI version 13.1.3. Development server Run ng serve for a dev server. Navigate to http://localhost:4

null 5 Aug 11, 2022
Reactive Extensions for Angular

RxAngular offers a comprehensive toolset for handling fully reactive Angular applications with the main focus on runtime performance and template rendering.

RxAngular 1.5k Jan 5, 2023
Semantic UI Angular Integrations

Semantic-UI-Angular Semantic-UI-Angular is a pure AngularJS 1.x set of directives for Semantic-UI components. We are considering Angular 2 support in

Semantic Org 561 Dec 28, 2022
The code for a set of Angular 6+ components for the PatternFly project.

The code for a set of Angular 6+ components for the PatternFly project. Note that the release/3.x branch supports Angular 4 and 5.

PatternFly 87 Nov 15, 2022
Angular 11 & Bootstrap 5 & Material Design 2.0 UI KIT

MDB 5 Angular Angular 12 & Bootstrap 5 & Material Design 2.0 UI KIT >> Get Started in 4 steps >> MDBAngular 5 Demo 500+ material UI components Super s

MDBootstrap 1.1k Dec 30, 2022