{"id":22672372,"url":"https://github.com/jimlynchcodes/ngrx-effect-chaining-example","last_synced_at":"2025-10-14T21:05:54.643Z","repository":{"id":74887809,"uuid":"82595407","full_name":"JimLynchCodes/Ngrx-Effect-Chaining-Example","owner":"JimLynchCodes","description":"Angular 2 project showing one way to \"chain\" side effects with @Effects.","archived":false,"fork":false,"pushed_at":"2023-10-14T18:45:40.000Z","size":28811,"stargazers_count":17,"open_issues_count":2,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T12:31:05.898Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JimLynchCodes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2017-02-20T19:42:10.000Z","updated_at":"2025-02-17T20:45:18.000Z","dependencies_parsed_at":"2025-04-12T12:40:31.145Z","dependency_job_id":null,"html_url":"https://github.com/JimLynchCodes/Ngrx-Effect-Chaining-Example","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/JimLynchCodes/Ngrx-Effect-Chaining-Example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JimLynchCodes%2FNgrx-Effect-Chaining-Example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JimLynchCodes%2FNgrx-Effect-Chaining-Example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JimLynchCodes%2FNgrx-Effect-Chaining-Example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JimLynchCodes%2FNgrx-Effect-Chaining-Example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JimLynchCodes","download_url":"https://codeload.github.com/JimLynchCodes/Ngrx-Effect-Chaining-Example/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JimLynchCodes%2FNgrx-Effect-Chaining-Example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279021333,"owners_count":26087018,"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-14T02:00:06.444Z","response_time":60,"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":[],"created_at":"2024-12-09T16:19:04.454Z","updated_at":"2025-10-14T21:05:49.636Z","avatar_url":"https://github.com/JimLynchCodes.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Ngrx Effects Chaining Example\n\nThis repo is meant to demonstrate a few things:\n\n* \"Chaining\" Ngrx Effects\n* Canceling an Observable Stream in Ngrx\n* Login / Logout of Firebase *without getting database errors.* \n\n\u003cimg src=\"./screenshots/NgrxEffectChaining_front_page.png\" alt=\"Ngrx Effects\" width=\"350px\"/\u003e\n\nThis is a small and focused demo that begins with only a single button, the login button. Once it is clicked the user is anonymously authenticated through Firebase. Then the text in the middle card should update to display some text from the Firebase database. Once logged in the user is presented with two other buttons.\n\n\u003cimg src=\"./screenshots/NgrxEffectChaining_logout_choices.png\" alt=\"Ngrx Effects\" width=\"350px\"/\u003e\n\nThe red button is the naiive logout approach which basically just calls the firebase logout method. I purposely put this in this project to demonstrate the problem with doing this. Since pulling from Firebase database is basically opening a websocket stream, signing out prevents you from acessing the stream and completely breaks the observable listening to the firebase database. If you have your debugging console open you should see a flood of red text when you click the red logout button.\n\n\u003cimg src=\"./screenshots/NgrxEffectChaining_logout_error.png\" alt=\"Ngrx Effects\" width=\"350px\"/\u003e\n\nOn the other hand, the green button first closes the open Firebase database websocket. Then once that has finished the user is logged out. This makes for a very nice, error-free experience. ahhh, how refreshing.\n\n## Effect Chaining\n\nI'm a huge fan of Ngrx/store, a reactive Redux library for Angular 2. Of course, once you get into it you realize that you need Ngrx/effects for handling asynchronous events (or you should, at least)! I wanted a clean way of having various effects execute in a sequence. For example, when signing out I want to first close the Firebase database observable and then immediately after it finishes successfully sign out. \n\nTake a look at the three effects here:\n\n```\n@Effect()\n  dbCloseSocket$ = this.action$\n    .ofType(MainActionTypes.CLOSE_DB_SOCKET_BEGIN)\n    .mergeMap((g) =\u003e {\n      return Observable.of(this.dbSocket.$ref.off())\n        .flatMap(payload =\u003e {\n          return Observable.of(new CloseDbSocketSuccess())\n        })\n    });\n\n\n  @Effect()\n  closeDbSocketToSignOutChain$ = this.action$\n    .ofType(MainActionTypes.CLOSE_DB_SOCKET_SUCCESS)\n    .switchMap(() =\u003e\n      Observable.of(new SignOutBegin())\n    );\n\n  @Effect()\n  signOut$ = this.action$\n    .ofType(MainActionTypes.SIGN_OUT_BEGIN)\n    .mergeMap((g) =\u003e {\n      return Observable.fromPromise(this.af.auth.logout())\n        .flatMap(payload =\u003e {\n          return Observable.of(new SignOutSuccess())\n        })\n\n    });\n```\n\nThe first, dbCloseSocket$, takes in a CLOSE_DB_SOCKET_BEGIN action, closes the websocket using \"$ref.off()\", and then returns an observable of the CLOSE_DB_SOCKET_SUCCESS action.\n\nThe third effect, signOut$, takes in a SIGN_OUT_BEGIN action, signs the user out with \"af.auth.logout()\", and then returns an observable of the SIGN_OUT_SUCCESS action.\n\n**In general, effects that \"do something\" should always take in a \"begin\" action and should return a \"success\" (or \"failure\") action.**\n\nI have found that this is the easiest approach for debugging, maintaining the codebase, and just figurign out what the heck is going on in an app where there's actions firing all over the place.\n\nNotice that in the second effect there is no async event taking place and that it's \"begin\" action and \"success\" action don't match each other. This is what I call a \"chaining effect\", and I sometiems refer to it as an \"empty effect\" beacuse there is no interesting async stuff happening here. It literally just takes in the \"CLOSE_DB_SOCKET_SUCCESS\" action and returns a \"SIGN_OUT_BEGIN\" action. When writing our effects in this way we get a very nice \"story\" of the sequence of actions that are being fired off, and we can see these in the redux chrome extension: \n\n\u003cimg src=\"./screenshots/NgrxEffectChaining_redux_dev_tools.png\" alt=\"Ngrx Effects\" width=\"350px\"/\u003e\n\n## Usage\n\nThis project was generated with [angular-cli](https://github.com/angular/angular-cli) version 1.0.0-beta.28.3.\n\n### Install Dependencies\n\n`npm install`\n\n### Development server\nRun `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.\n\n### Code scaffolding\n\nRun `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.\n\n### Build\n\nRun `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.\n\n## Running unit tests\n\nRun `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).\n\n### Running end-to-end tests\n\nRun `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).\nBefore running the tests make sure you are serving the app via `ng serve`.\n\n### Deploying to GitHub Pages\n\nRun `ng github-pages:deploy` to deploy to GitHub Pages.\n\n### Further Help\n\nTo get more help on the `angular-cli` use `ng help` or go check out the [Angular-CLI README](https://github.com/angular/angular-cli/blob/master/README.md).\n\n### Shoutouts \n\n* Thanks to Xavier Lozinguez for helping intitially me understand the quirks of Ngrx and being my only friend in NYC who loves Ngrx as much as I do.\n\n* Also, big thanks to Andrew Woods for reading my blogs posts, for bringing the \"Firebase logout while the socket's still open\" issue into the light, and for updating me with his own code which was a huge inspiration for this project. Thanks, buddy.\n\n### One More Thing\nNot sure if it matters, but I'm using node v6.9.2, npm v3.10.9, and angular cli v1.0.0-beta.28.3\n\nCheers! 🍻 \n-- Jimbo\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimlynchcodes%2Fngrx-effect-chaining-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjimlynchcodes%2Fngrx-effect-chaining-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjimlynchcodes%2Fngrx-effect-chaining-example/lists"}