Notifications
Mark all as read
Q&A

How to create a delayed loading indicator when working with ngrx/store?

+1
−0

I am working on an Angular application using ngrx and I have a loader state + reducer that is used to display a loader. However, very short AJAX calls cause a flicker and I need to delay showing the loaded to avoid being shown for very fast responses (e.g. < 300ms).

My state is very simple:

export interface LoadingState {
    isLoading: boolean;
    loaderMessage: string;
}

export const initialLoadingState: LoadingState = {
    isLoading: false,
    loaderMessage: ""
};
Why should this post be closed?

0 comments

1 answer

+0
−0

This heavily relies on this question which deals with another matter.

In order to delay the loader, there must be a clear difference between the start of loaded from the caller's perspective and when the loader is actually displayed (i.e. isLoading = true).

The following code does the trick:

The reducer

export const loadingReducerInner = createReducer(
	initialLoadingState,
	on(LoadingSetVisibleAction, (state) => {
			return {
				isLoading: true,
				loaderMessage: state.loaderMessage
			};
	}),
	on(LoadingEndedAction, _ => {
			return {
				isLoading: false,
				loaderMessage: ""
			};
	})
);

export function loadingReducer(state: LoadingState, action: Action): LoadingState {
	return loadingReducerInner(state, action);
}

The effect

There are two possible things that might happen:

  • the load is fast enough (<500ms in this case) and LoadingSetVisibleAction is not called because a LoadingEndedAction will be dispatched

  • the load is slower and the loader is set to true before LoadingEndedAction is dispatched

    @Injectable()
    export class LoadingEffects {
    
      constructor(private actions$: Actions) { }
    
      startDelayTimer$ = createEffect(() => this.actions$.pipe(
      		ofType(LoadingStartedAction),
      		switchMap(_ => {
      			const ret$ = timer(500).pipe(
      				takeUntil( this.actions$.pipe(ofType(LoadingEndedAction))),
      				mapTo(LoadingSetVisibleAction())
      			);
      			return ret$;
      		})
      	));
    

    }

Of course, the caller must ensure that LoadingStartedAction is always paired with a LoadingEndedAction dispatch both on positive and negative (an exception is raised during the AJAX call) flows.

0 comments

Sign up to answer this question »