{"id":31642224,"url":"https://github.com/pavannpk/angular-ngrx","last_synced_at":"2026-04-21T03:31:20.952Z","repository":{"id":306653003,"uuid":"1026862068","full_name":"pavanNPK/Angular-NGRX","owner":"pavanNPK","description":"NgRx is a state management library for Angular. It centralizes app data and uses actions, reducers, selectors, and effects. You dispatch actions (e.g., addEmployee), reducers update state, selectors fetch data, and effects handle side effects like API calls.","archived":false,"fork":false,"pushed_at":"2025-07-26T19:17:11.000Z","size":225,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-26T23:33:49.062Z","etag":null,"topics":["actions","redcucers","selectors","store"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pavanNPK.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-26T19:15:40.000Z","updated_at":"2025-07-26T19:20:30.000Z","dependencies_parsed_at":"2025-07-26T23:33:52.388Z","dependency_job_id":"1238ff83-c0cc-438a-ab0c-8e4cbef65321","html_url":"https://github.com/pavanNPK/Angular-NGRX","commit_stats":null,"previous_names":["pavannpk/angular-ngrx"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/pavanNPK/Angular-NGRX","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavanNPK%2FAngular-NGRX","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavanNPK%2FAngular-NGRX/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavanNPK%2FAngular-NGRX/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavanNPK%2FAngular-NGRX/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pavanNPK","download_url":"https://codeload.github.com/pavanNPK/Angular-NGRX/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pavanNPK%2FAngular-NGRX/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278717450,"owners_count":26033542,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-07T02:00:06.786Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actions","redcucers","selectors","store"],"created_at":"2025-10-07T03:57:15.701Z","updated_at":"2025-10-07T03:57:29.315Z","avatar_url":"https://github.com/pavanNPK.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Angular NgRx Example\n\nThis project demonstrates how to use **NgRx**, a state management library for Angular applications. NgRx helps manage application state in a clear, scalable, and predictable way by leveraging the Redux pattern and RxJS.\n\n---\n\n## 📦 What is NgRx?\n\n**NgRx** provides a single source of truth for your application's data using a central **Store**. All changes to this data flow in one direction, making state updates easy to track, debug, and reason about.\n\nNgRx is a state management library for Angular that uses the Redux pattern. It helps you manage application data in a centralized way using Actions, Reducers, Selectors, and Effects. Think of NgRx like a single “data brain” for your app — instead of having different components manage their own data, everything flows through the store, which is a global, reactive data container. When something happens (like clicking a button), you dispatch an Action (e.g., addEmployee). The Reducer takes this action and updates the store immutably. Your components then select the updated data from the store using Selectors. If data needs to be fetched from an API, you use Effects, which listen for specific actions and perform asynchronous work like HTTP calls. For example, if you want to add a new employee, you might dispatch addEmployeeAction({ data }), an Effect catches it and calls an API, and once it succeeds, it dispatches addEmployeeSuccessAction, which the Reducer uses to update the store with the new employee. The UI then automatically reflects this new data — no need to manage complex manual updates. NgRx keeps your logic organized, testable, and scalable, especially in large apps.\n\n---\n\n## 🚩 Key Features and Examples\n\n### 1. Centralized State Management\n\nManage your app's data in one place: the Store. Any component can read from or update the state.\n\n```angular181html\n// Define the shape of your cart state\ninterface CartState {\n    items: Book[];\n}\n\n// Initial state\nconst initialState: CartState = {\n    items: []\n};\n```\n\n---\n\n### 2. Predictable State Updates (Actions and Reducers)\n\nState changes happen via **Actions** and are handled by **Reducers**. Data always flows in a single direction.\n\n```angular181html\n// Action: Add a book to the cart\nimport { createAction, props } from '@ngrx/store';\n\nexport const addBook = createAction(\n  '[Cart] Add Book',\n  props\u003c{ book: Book }\u003e()\n);\n\n// Reducer: Handle adding books\nimport { createReducer, on } from '@ngrx/store';\n\nconst cartReducer = createReducer(\n  initialState,\n  on(addBook, (state, { book }) =\u003e ({\n  ...state,\n  items: [...state.items, book]\n  }))\n);\n```\n\n---\n\n### 3. Handling Side Effects (Effects)\n\nUse **Effects** to handle asynchronous operations, like API calls, outside of your components.\n\n```angular181html\nimport { createEffect, ofType, Actions } from '@ngrx/effects';\nimport { switchMap, map } from 'rxjs/operators';\n\nloadBooks$ = createEffect(() =\u003e\n  this.actions$.pipe(\n    ofType(loadBooks),\n    switchMap(() =\u003e this.bookService.getBooks()),\n    map(books =\u003e loadBooksSuccess({ books }))\n  )\n);\n```\n\n---\n\n### 4. Scalability and Maintainability\n\nNgRx enforces a structured approach, making large and growing apps **easier to extend and maintain**.\n\n*Example*: To add new features (like book reviews), introduce new actions, reducers, and selectors—without disturbing unrelated logic.\n\n---\n\n### 5. Debugging with NgRx DevTools\n\nNgRx integrates with DevTools for **time-travel debugging**. See every action and resulting state, move back and forth through state history, and pinpoint issues quickly.\n\n---\n\n### 6. Efficient Data Sharing Between Components\n\nAny component can select data from the store using selectors—no need for prop drilling or repetitive service logic.\n\n```angular181html\nthis.cart$ = this.store.select(selectCartItems);\n```\n\n---\n\n### 7. Performance Optimization\n\nNgRx uses **RxJS and immutable updates**, so only the parts of the UI that need to update will do so, reducing unnecessary re-renders.\n\n---\n\n## 🔄 Typical NgRx Data Flow\n\n1. **Component** dispatches an **Action** (e.g., \"Add to cart\").\n2. **Action** is handled by a **Reducer** (to update state) or an **Effect** (to handle an async task).\n3. The **Store** updates the state.\n4. Components **select** the necessary state and update their display.\n\n---\n\n## 📚 Learn More\n\n- Official Docs: [NgRx Documentation](https://ngrx.io/docs)\n- Example Tutorials: [NgRx Store](https://ngrx.io/guide/store)\n- Further Reading: [State Management in Angular Using NgRx Pt 1][6]\n\n---\n\n## 🛠️ Installation\n\n```angular181html\nnpm install @ngrx/store @ngrx/effects --save\n\nit'll update the `package.json` file and `app.config.ts` which is for 16+ `provideStore()` for below it'll update the `app.module.ts` which is `StoreModule.forRoot()`.\n```\n\n---\n\n## 📁 Project Structure Example\n\n```angular181html\nsrc/\napp/\ncore/\nstate/\ncart/\ncart.actions.ts\ncart.reducer.ts\ncart.effects.ts\ncart.selectors.ts\n```\n\n---\n\nNgRx helps keep your Angular applications *organized*, *scalable*, and *easier to debug*, especially as they grow in complexity.\n\n![img.png](public/img.png)\n\n#### Summary\n- **NGRX** it's simply like share the data across the application. with the centralized state management.\n- It's store the data in one place called the `store`. \n- Any component can read from or update (means copy the new one it'll never update the data. it'll copy the new updated data) the state by `subscribing` to the `store`.\n- State changes happen via `actions` and are handled by `reducers`.\n- Data always flows in a single direction.\n- Use `effects` to handle asynchronous operations, like API calls, outside of your components. it's send to `actions` to `reducer` and update the store.\n- NgRx enforces a structured approach, making large and growing apps easier to extend and maintain.\n- NgRx integrates with DevTools for time-travel debugging.\n- Any component can select data from the store using selectors.\n- NgRx uses RxJS and immutable updates, so only the parts of the UI that need to update will do so, reducing unnecessary re-renders.\n- Store has separate logic. if we want we can write the store logic in `Reducers`\n\n-----\n\n- In `NgRx`, `selectors` are pure functions used to extract, transform, and compose slices of state from the NgRx store. They provide a powerful and efficient way to access data within your application's state management.\n\n----\n### Let's Start\n\n- I have created the store with the `count.reducer.ts` and in that i initialized the value to `1`.\n- I exported the createReducer function from the `@ngrx/store` package. and mentioned the type `number` in the `createReducer` function.\n- Firstly, I placed the initial value.\n- \n```angular181html\nimport { createReducer } from '@ngrx/store';\n\n// Define the initial state\nconst initialState = 10;\n\n// Create the reducer with proper typing\nexport const counterReducer = createReducer\u003cnumber\u003e(\n    initialState,\n);\n```\n- After that, I placed the `counterReducer` in the `provideStore` in the `app.config.ts` file.\n\n```angular181html\nimport { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';\nimport { provideRouter } from '@angular/router';\nimport { provideStore } from '@ngrx/store';\nimport {counterReducer} from './store/count.reducer';\n\nexport const appConfig: ApplicationConfig = {\n    providers: [\n        provideRouter([]),\n        provideStore({ counterNumber: counterReducer }),\n        provideZoneChangeDetection(),\n    ],\n};\n```\n\n- Then, we can access the store in the component.\n- I created the `Observable` `counterValue$` to get the value from the store. This is one method to get the data by subscribing to the store.\n- I created the `Observable` `counterValueSelector$` to get the value from the store. This is one method to get the data by using `selector` to get the value.\n- It will return the `Observable` again, so we need to subscribe to it. so we can directly use the `async pipe` to get the data.\n\n```angular181html\ncounterValue$: any\ncounterValueSelector$: any\n\nwe need to use constructor to get the value\nconstructor(private realStore:Store\u003cany\u003e) {\n    this.realStore.subscribe(state =\u003e {\n        this.counterValue = state.counterNumber;\n    });\n    this.counterValueSelector$ = this.realStore.select('counterNumber');\n  }\n\n  \u003cp\u003eGetting count from store observable: {{counterValue$}}\u003c/p\u003e\n  \u003cp\u003eGetting count from store selector: {{counterValueSelector$ | async}}\u003c/p\u003e\n```\n----\n\n### Discuss about Actions, dispatch actions\n\n#### **Step 1**: Create Actions - Counter\n\n```angular181html\nimport { createAction } from '@ngrx/store';\n\nexport const increment = createAction('[Counter] Increment');\nexport const decrement = createAction('[Counter] Decrement');\nexport const reset = createAction('[Counter] Reset');\n```\n##### What is createAction?\n\n`createAction` is a utility function from NgRx used to define actions in a type-safe and consistent way.\n\n**What is an action?**\n- An action is an instruction that tells the store what happened — like:\n  - \"User clicked increment\"\n  - \"Item was deleted\"\n  - \"API returned success\"\n- It usually includes:\n  - The type of the action\n  - Optional payload/data\n\n**Why This Format?**\n```angular181html\n'[Test for Ngrx] Count Increase'\n\n[Source] Event description\n\n[Source]\n\n- This is a convention that helps identify where the action comes from.\n- In this case: [Test for Ngrx] — this might be a component or feature name.\n- Makes it easier to debug and log actions.\n```\n\n**Event description**\n\n- Describes what happened — e.g., Count Increase, Count Decrease.\n\n| Feature                  | Why It's Useful                                      |\n| ------------------------ | ---------------------------------------------------- |\n| `[Source] Action` format | Helps in debugging, filtering logs, grouping actions |\n| Named action constants   | Avoids typos, provides auto-complete, type safety    |\n| `createAction()`         | Gives strongly-typed action creators                 |\n\n---\n\n#### **Step 2**: Create Reducers - Counter\n\n```angular181html\nimport { createReducer, on } from '@ngrx/store';\nimport { increment, decrement, reset } from './counter.actions';\n\nconst initialState = 0;\n\nexport const counterReducer = createReducer(\n  initialState,\n  on(increment, (state) =\u003e state + 1),\n  on(decrement, (state) =\u003e state - 1),\n  on(reset, (state) =\u003e 0)\n);\n```\n\n#### **Step 3**:Use in Component - Counter\n```angular181html\nimport { Store } from '@ngrx/store';\nimport { increment, decrement, reset } from './counter.actions';\n\nconstructor(private store: Store\u003c{ counter: number }\u003e) {}\n\nincrement() {\n  this.store.dispatch(increment());\n}\n\ndecrement() {\n  this.store.dispatch(decrement());\n}\n\nreset() {\n  this.store.dispatch(reset());\n}\n```\n\n### Summary\n\n| Concept             | Description                                                |\n| ------------------- | ---------------------------------------------------------- |\n| `createAction`      | Used to define a new action                                |\n| `[]` in action type | Convention to group actions by feature/module              |\n| `Count Increase`    | Description of what the action does                        |\n| Benefit             | Clean, readable, and maintainable action structure in NgRx |\n\n\n### now we can do CRUD with NgRx\n- Dashboard\n- Employee List / Create / Edit / Delete\n\n**By Store:** We can access the data from the store.\n- We can load the data from the store.\n- We can update the data in the store.\n- We can delete the data in the store.\n- We can add the data in the store.\n\n**We need follow some steps:**\n\n\n- Created the reducer file and placed the initial value. then we need to import in the `app.module.ts` file. Which is `provideStore()` in that `provideStore({ employees: createDataReducer() })`\n\n```angular181html\nexport const createDataReducer = createReducer(\ninitialState, // its an array of obj which is employees\n);\n```\n\n- Later created the action file and placed the actions.\n- We need to pass the id in the action.\n\n```angular181html\nexport const deleteEmployeeAction = createAction('[Employees List] Delete Employee', (id: number) =\u003e ({id}));\n```\n\n- Later we need to register the action in the reducer.\n\n```angular181html\nexport const createDataReducer = createReducer(\n  initialState,\n  on(deleteEmployeeAction, (state, {id}) =\u003e {\n    return {\n      ...state,\n      employees: state.employees.filter((emp) =\u003e emp.id !== id),\n    };\n  })\n);\n```\n- Later we need to dispatch the action in the component.\n\n```angular181html\ndeleteEmployee(id: any) {\n  console.log(id);\n  // here we can dispatch action\n  this.realStore.dispatch({\n  type: '[Employees List] DELETE_EMPLOYEE',\n  id});\n}\n```\n\n```angular181html\ncreateEmployee(){\n  if (this.employeeForm.invalid) {\n    return;\n  } else {\n    console.log(this.employeeForm.value);\n    this.realStore.dispatch({\n      type: '[Employees List] CREATE_EMPLOYEE',\n      data: this.employeeForm.value\n    });\n    this.route.navigate(['employees']);\n  }\n}\n```\n\n\n```angular181html\non(createEmployeeAction, (state, {data}) =\u003e {\n  console.log(data, state, '.....');\n    let obj  = {\n    id: 0,\n    ...data\n  }\n  obj.id = state.employees[state.employees.length - 1].id + 1;\n  return {\n    ...state,\n    employees: [...state.employees, obj],\n  };\n})\n```\n\n```angular181html\nngOnInit(): void {\n  // Initialize form first\n  this.employeeForm = this.fb.group({\n    id: ['', Validators.required],\n    name: ['', Validators.required],\n    salary: ['', Validators.required]\n  });\n  \n  // Get route param and fetch employee\n  this.route.params.subscribe(params =\u003e {\n    this.employeeId = +params['id'];\n    \n    this.store.select('employeesData').subscribe((val) =\u003e {\n      const employee = val.employees?.find((emp: any) =\u003e emp.id === this.employeeId);\n      \n      if (employee) {\n        this.employeeForm.patchValue(employee);\n      } else {\n        console.warn(`Employee with id ${this.employeeId} not found.`);\n      }\n      \n      this.employeesData$ = val.employees;\n    });\n  });\n}\n```\n\n\n```angular181html\nupdateEmployee() {\n  if (this.employeeForm.valid) {\n    const updatedEmployee = this.employeeForm.value;\n    console.log('Updating employee:', updatedEmployee);\n    \n    // Dispatch update action here if using NgRx\n    this.store.dispatch({\n    type: '[Employees List] UPDATE_EMPLOYEE',\n    data: updatedEmployee});\n    // Optionally navigate back\n    this.backToList();\n  } else {\n    this.employeeForm.markAllAsTouched();\n  }\n}\n```\n\n```angular181html\non(updateEmployeeAction, (state, { data }) =\u003e {\n  const exists = state.employees.some(emp =\u003e emp.id === data.id);\n  \n  return {\n    ...state,\n    employees: exists ? state.employees.map(emp =\u003e emp.id === data.id ? data : emp)\n    : [...state.employees, data]\n  };\n})\n```\n\n\n###### **Any Doubt?** Refer the exact flow:\n - First check store/data.reducer.ts\n - Then check store/data.actions.ts\n - Then check employees-list/employees-list.component.ts\n - What we have done here. Create the dummy data in reducer in initial value. then we need to import in the `app.module.ts` file. Which is `provideStore()` in that `provideStore({ employees: createDataReducer() })`\n - Later we use constructor to get the value from the store in the component of employees list. Then we use the selector to get the value in the template.\n - Then once data is loaded. Then we cretaed the `actions` in that creation of maintaied the `type` and `id` of it because of we are doing `deletion` here.\n - Then we need to pass the id in the action.\n - Then we need to register the action in the reducer.\n - Then we need to dispatch the action in the component. - \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavannpk%2Fangular-ngrx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpavannpk%2Fangular-ngrx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpavannpk%2Fangular-ngrx/lists"}