Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save hrvbernardic/0ea5d37384719b992e37af1ea0424507 to your computer and use it in GitHub Desktop.
Save hrvbernardic/0ea5d37384719b992e37af1ea0424507 to your computer and use it in GitHub Desktop.
import { inject, Injectable } from '@angular/core';
import { NonNullableFormBuilder } from '@angular/forms';
import { ComponentStore, OnStateInit, tapResponse } from '@ngrx/component-store';
import { of } from 'rxjs';
import { switchMap, tap, withLatestFrom } from 'rxjs/operators';
export interface User {
id: number;
name: string;
}
export interface UserComponentState {
status: {
state: 'loading' | 'loaded' | 'loaded_last' | null;
type: 'success' | 'error' | null;
},
criteria: {
page: number;
pageSize: number;
query: string | null;
},
response: User[] | null
}
@Injectable()
export class UserComponentStore extends ComponentStore<UserComponentState> implements OnStateInit {
// connect to URL, if need it
readonly form = inject(NonNullableFormBuilder).group({
query: ''
})
constructor() {
super({
status: {
state: null,
type: null,
},
criteria: {
page: 1,
pageSize: 20,
query: null
},
response: null
})
}
ngrxOnStateInit() {
this.effect(() => this.form.valueChanges.pipe(
tap(criteria => {
this.fetch(criteria);
})
))
}
/** SELECTORS */
private readonly status$ = this.select((state) => state.status);
private readonly criteria$ = this.select((state) => state.criteria);
private readonly response$ = this.select((state) => state.response);
readonly vm$ = this.select(
this.status$,
this.criteria$,
this.response$,
(status, criteria, response) => ({
status,
criteria,
response,
}),
{ debounce: true }
);
/** UPDATERS */
readonly setStatus = this.updater((state, status: UserComponentState['status']) => ({
...state,
status,
}));
readonly setCriteria = this.updater((state, criteria: Partial<UserComponentState['criteria']>) => ({
...state,
criteria: {
...state.criteria,
...criteria,
},
}));
readonly setResponse = this.updater((state, response: UserComponentState['response']) => ({
...state,
response,
}));
/** EFFECTS */
readonly fetch = this.effect<Partial<UserComponentState['criteria']> | void>((value$) => {
return value$.pipe(
tap((criteria) => {
if (criteria) {
this.setCriteria(criteria);
}
this.setStatus({
state: 'loading',
type: null
});
}),
withLatestFrom(this.criteria$),
switchMap(([, criteria]) => of(null).pipe(
tapResponse(
(res) => {
this.setResponse(res);
this.setStatus({
state: 'loaded',
type: 'success',
});
},
() => {
this.setStatus({
state: 'loaded',
type: 'error',
});
}
))
)
)
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment