Angular NgRx State Management Challenge
This challenge focuses on implementing NgRx, a popular state management library for Angular applications. You will be tasked with building a simple feature that manages a list of items using NgRx, demonstrating your understanding of actions, reducers, selectors, and the store. Mastering NgRx is crucial for building scalable and maintainable Angular applications with complex state.
Problem Description
Your goal is to create a basic "Todo List" feature within an Angular application using NgRx. This feature will allow users to add new todo items, mark existing items as completed, and view the current list of todos.
Key Requirements:
- Setup NgRx: Configure your Angular project to use NgRx, including installing the necessary packages and setting up the
StoreModule. - Define State: Create a clear interface for your todo item (e.g.,
id,text,completed) and define the overall state of your todo list (e.g., an array of todo items). - Create Actions: Define NgRx actions for the following operations:
AddTodo: To add a new todo item.ToggleTodoCompletion: To toggle the completion status of a specific todo item.
- Implement Reducer: Write a reducer function that handles the defined actions and updates the state accordingly. The reducer should be a pure function.
- Create Selectors: Develop NgRx selectors to efficiently retrieve specific pieces of state from the store (e.g., all todos, or a specific todo by ID).
- Integrate with Component: Connect your Angular component to the NgRx store. Dispatch actions from the component based on user interactions and subscribe to state changes using selectors to update the UI.
Expected Behavior:
- Users can type a new todo item in an input field and click an "Add" button to add it to the list.
- Each todo item in the list should have a way to toggle its completion status (e.g., a checkbox or a click event on the item itself).
- Completed todos should visually indicate their completed state (e.g., strikethrough text).
- The component should reflect the current state of the todo list as managed by the NgRx store.
Edge Cases:
- Adding an empty todo item should not add it to the list.
- Toggling completion on a non-existent todo item should not cause an error.
Examples
Example 1: Adding a Todo
Input:
User types "Buy groceries" and clicks "Add".
Output:
The todo list now displays:
- Buy groceries (not completed)
Explanation:
The AddTodo action is dispatched with the text "Buy groceries". The reducer updates the state by adding a new todo object to the list. The component, subscribed to the todo list selector, re-renders to show the new item.
Example 2: Toggling Completion
Input:
Current todo list:
- Buy groceries (not completed)
User clicks on "Buy groceries" to mark it as completed.
Output:
The todo list now displays:
- ~~Buy groceries~~ (completed)
Explanation:
The ToggleTodoCompletion action is dispatched with the ID of "Buy groceries". The reducer finds the corresponding todo item and updates its completed property to true. The component, subscribed to the todo list selector, re-renders to show the updated visual state.
Example 3: Adding an Empty Todo
Input:
User clicks "Add" with an empty input field.
Output:
The todo list remains unchanged.
Explanation:
The component should prevent dispatching the AddTodo action if the input is empty, or the reducer should handle an empty todo text gracefully by not adding it.
Constraints
- Your Angular version should be
^15.0.0or later. - NgRx packages must be installed using
npmoryarn. - The solution should be implemented in TypeScript.
- The entire state management logic (actions, reducers, selectors) should be encapsulated within a dedicated NgRx feature module or a dedicated NgRx file structure.
Notes
- Consider using the NgRx schematics for setting up your NgRx entities.
- For generating unique IDs for todo items, you can use libraries like
uuidor a simple counter. - Focus on correctly implementing the core NgRx patterns. The UI styling and component logic beyond state integration are secondary.
- Ensure your reducer is a pure function and does not mutate the original state.
- Think about how to access specific parts of your state efficiently using selectors.