This tutorial is based on the contact form in angularmicrotutorials. It traces a user submission through NgRx actions, an effect, a reducer, and selectors. Important scope note: the current effect simulates a successful asynchronous response with RxJS of(); it does not send the form to HubSpot or any backend.
1. Define the state
The contact feature tracks successful submissions, request status, and an optional error. The state is in memory, so it resets when the application reloads.
export interface ContactState {
submissions: ContactSubmission[];
loading: boolean;
error: string | null;
}
export const initialContactState: ContactState = {
submissions: [],
loading: false,
error: null
};
2. Describe user events with actions
Actions name events and carry the data needed to handle them. The form dispatches submitContact; the effect later dispatches a success or failure action.
export const submitContact = createAction(
'[Contact] Submit Contact',
props<{ name: string; email: string; message: string }>()
);
export const submitContactSuccess = createAction(
'[Contact] Submit Contact Success',
props<{ submission: ContactSubmission }>()
);
3. Handle the side effect
The effect listens for the submit action and returns a simulated result. In a real integration, replace the of() expression with an HttpClient request; the success and failure action pattern can remain.
submitContact$ = createEffect(() =>
this.actions$.pipe(
ofType(submitContact),
mergeMap((action) =>
of({
name: action.name,
email: action.email,
message: action.message,
createdAt: new Date().toISOString()
}).pipe(
map((submission) => submitContactSuccess({ submission })),
catchError((error) =>
of(submitContactFailure({ error: error.message }))
)
)
)
)
);
4. Update state immutably
The reducer sets loading on submit, appends the successful entry, and stores an error on failure. Each handler returns a new state object rather than mutating the old one.
on(submitContact, (state) => ({
...state,
loading: true,
error: null
})),
on(submitContactSuccess, (state, { submission }) => ({
...state,
submissions: [...state.submissions, submission],
loading: false,
error: null
}))
5. Select state for the UI
The component dispatches the action and reads submissions, loading, and error through selectors. The template disables the submit button during loading and can show the error or in-memory history.
Key takeaway
Actions describe intent, effects handle asynchronous work, reducers update state, and selectors expose state to the UI. This tutorial demonstrates the architecture; persistence and backend communication are separate follow-up exercises.
Leave A Comment
You must be logged in to post a comment.