{"id":14973199,"url":"https://github.com/nodonisko/ionic-cache","last_synced_at":"2025-04-12T23:39:52.111Z","repository":{"id":8728147,"uuid":"59506875","full_name":"Nodonisko/ionic-cache","owner":"Nodonisko","description":"Angular cache service with IndexedDB, SQLite  and WebSQL support","archived":false,"fork":false,"pushed_at":"2023-02-27T23:22:04.000Z","size":1621,"stargazers_count":261,"open_issues_count":11,"forks_count":73,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-04-12T23:39:45.880Z","etag":null,"topics":["angular","angular2","cache","ionic","offline","support-indexeddb","websql"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nodonisko.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2016-05-23T18:07:33.000Z","updated_at":"2025-02-08T04:44:10.000Z","dependencies_parsed_at":"2024-06-18T13:58:25.272Z","dependency_job_id":"1bd47ece-3079-4c2a-a84f-8cf825fb4ba1","html_url":"https://github.com/Nodonisko/ionic-cache","commit_stats":{"total_commits":195,"total_committers":25,"mean_commits":7.8,"dds":0.7128205128205128,"last_synced_commit":"8baa0c0f563dd37bb0adbcfd394788fb79b63cf5"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nodonisko%2Fionic-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nodonisko%2Fionic-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nodonisko%2Fionic-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nodonisko%2Fionic-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nodonisko","download_url":"https://codeload.github.com/Nodonisko/ionic-cache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248647255,"owners_count":21139081,"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","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":["angular","angular2","cache","ionic","offline","support-indexeddb","websql"],"created_at":"2024-09-24T13:48:21.581Z","updated_at":"2025-04-12T23:39:52.087Z","avatar_url":"https://github.com/Nodonisko.png","language":"TypeScript","readme":"# Ionic cache service\n\nIonic cache service that can cache almost everything. **It caches requests, observables, promises and classic data.** It uses [Ionic Storage](https://ionicframework.com/docs/storage/) so we support IndexedDB, SQLite (Cordova), WebSQL in this order.\nIt can be used separatelety in Angular 2 application.\n\nKey features:\n\n-   Request caching\n-   Delayed observable caching (see docs for more info)\n-   Don't invalidate cache if is browser offline\n-   Set and invalidate groups of entries\n-   Supports IndexedDB, SQLite (Cordova), WebSQL via Ionic Storage\n\nPlease report all bugs to bug report or fix it and send pull request :)\n\n## Install\n\nVia NPM:\n\n```bash\nnpm install ionic-cache @ionic/storage-angular --save\n```\n\nor Yarn:\n\n```bash\nyarn add ionic-cache @ionic/storage-angular\n```\n\nYou can optionally add [Cordova SQLite](https://ionicframework.com/docs/native/sqlite/).\n\nAnd inject service to your app:\n\n_app.module.ts_\n\n```ts\nimport { CacheModule } from \"ionic-cache\";\n\n@NgModule({\n  ...\n  imports: [\n    CacheModule.forRoot()\n  ],\n})\n```\n\n_app.component.ts_\n\n```ts\nimport { CacheService } from \"ionic-cache\";\n\n@Component({\n    templateUrl: \"build/app.html\"\n})\nclass MyApp {\n    constructor(cache: CacheService) {\n        ...\n        cache.setDefaultTTL(60 * 60); //set default cache TTL for 1 hour\n        ....\n    }\n    ...\n}\n```\n\n## Usage\n\n### Config\n\nStarting with version 3.0.2, `CacheModule.forRoot()` optionally accepts a config object.\n\nThe config object currently accepts a `keyPrefix`, which is the the internal key prefix to use when storing items.\n\nFor backwards compatibility this defaults to `''`, but it's recommended to set this to a different value in order to prevent issues with `clearAll()`.\n\n```ts\n@NgModule({\n  ...\n  imports: [\n    CacheModule.forRoot({ keyPrefix: 'my-app-cache' })\n  ],\n})\n```\n\n### Observables\n\n#### Cache request\n\n```ts\n...\nimport { CacheService } from \"ionic-cache\";\n\n@Injectable()\nexport class SomeProvider {\n    constructor(private http: HttpClient, private cache: CacheService) {}\n\n    loadList() {\n        let url = \"http://ip.jsontest.com\";\n        let cacheKey = url;\n        let request = this.http.get(url);\n\n        return this.cache.loadFromObservable(cacheKey, request);\n    }\n    ...\n```\n\n#### Cache whole request response\n\nIf you need to cache the whole response, for example if you need to access the Headers, you can pass in an object with the observe key set to 'response', i.e. `{ observe: 'response' }`. Then you can use `.pipe(map(res =\u003e res.body))` to extract the response body.\n\n```ts\n...\nlet request = this.http.get(url, { observe: 'response' });\nreturn this.cache.loadFromObservable(cacheKey, request).pipe(map(res =\u003e res.body));\n...\n```\n\n#### Cache with custom Observable operators\n\n`loadFromObservable` accepts an Observable and returns an Observable, so you are free to use all of the Observable operators.\nFor example error handling (on error, retry request every 6 seconds if fails):\n\n```ts\n...\nlet request = this.http.get(url)\n.pipe(retryWhen(error =\u003e error.timer(6000)));\n\nreturn this.cache.loadFromObservable(cacheKey, request);\n...\n```\n\n#### Delayed observable caching\n\n`loadFromDelayedObservable` shows off the full power of observables.\nWhen you call this method and it will return the cached data (even if it's expired)\nand immediately send a request to the server and then return the new data.\n\n```ts\n...\n    let request = this.http.get(url);\n    let delayType = 'all'; // this indicates that it should send a new request to the server every time, you can also set it to 'none' which indicates that it should only send a new request when it's expired\n\n    let response = this.cache.loadFromDelayedObservable(cacheKey, request, groupKey, ttl, delayType);\n\n    response.subscribe(data =\u003e {\n        console.log(\"Data:\" data);\n    });\n\n    //result will look like this:\n    // Data: \"Hello world from cache\"\n    // Data: \"Hello world from server\"\n...\n```\n\n### Promises \u0026 Classic data\n\n#### Cache promises\n\n```ts\n...\nlet key = 'some-promise';\nlet data = await this.cache.getOrSetItem(key, () =\u003e somePromiseFunction());\nconsole.log(\"Saved data: \", data);\n...\n```\n\n#### Cache classic data (arrays, objects, strings, numbers etc.)\n\nSimilarly, you can use `getOrSetItem` or `getItem` with classic data.\n\n```ts\n...\nlet key = 'heavily-calculated-function';\n\nlet data = await this.cache.getOrSetItem(key, () =\u003e heavilyCalculatedFunction());\nconsole.log('Saved data: ', data);\n...\n```\n\nIf you need more control in the event that the item is expired or doesn't exist, you can use the `getItem` method with error handling.\n\n```ts\n...\nlet key = 'heavily-calculated-function';\n\nlet data = await this.cache.getItem(key)\n.catch(() =\u003e {\n    console.log(\"Oh no! My promise is expired or doesn't exist!\");\n\n    let result = heavilyCalculatedFunction();\n    return this.cache.saveItem(key, result);\n});\n\nconsole.log('Saved data: ', data);\n...\n```\n\n#### Removing cached items\n\nYou can also remove cached items by using the `removeItem` method.\n\n```ts\n...\nlet key = 'some-promise';\n\nthis.cache.removeItem(key);\n...\n```\n\n#### Removing multiple cached items\n\nYou can utilize the `removeItems` method to remove multiple items based on a wildcard pattern.\n\n```ts\n...\nawait Promise.all([\n    service.saveItem('movies/comedy/1', 'Scott Pilgrim vs. The World'),\n    service.saveItem('movies/comedy/2', 'The Princess Bride'),\n    service.saveItem('songs/metal/1', 'Who Bit the Moon'),\n    service.saveItem('songs/metal/2', 'Deception - Concealing Fate, Pt. 2'),\n]);\n\nthis.cache.removeItems('songs/metal/*');\n...\n```\n\n#### Cached promise existence\n\nIf you need to check whether or not an item has been cached, ignoring whether or not it's expired, you can use the `itemExists` method.\n\n```ts\n...\nlet key = 'some-promise';\n\nlet exists = await this.cache.itemExists(key); // returns either a boolean indicating whether it exists or not, or an error message\n...\n```\n\n#### Raw cached item\n\nIf you ever need to get a cached item regardless of whether it's expired or not, you can use the `getRawItem` method.\n\n```ts\n...\nlet key = 'some-promise';\n\nlet item = await this.cache.getRawItem(key);\n...\n```\n\nThere's also the `getRawItems` method, which returns an array of the raw cached items.\n\n```ts\n...\nlet rawItems = await this.cache.getRawItems();\nlet firstItem = rawItems[0]; //Has the properties: key, value, expires, type, groupKey\n...\n```\n\n### Other\n\n#### Cache entries grouping\n\nAt times you may need to clear certain groups of cached items.\nFor example, if you have an infinite scroll list with a lot of items and the user triggers a pull to refresh, you may want to delete all of the cached list items. To do this, you can supply a group key as the 3rd parameter of `loadFromObservable`.\n\n```ts\n...\nloadList(pageNumber) {\n    let url = \"http://google.com/?page=\" + pageNumber;\n    let cacheKey = url;\n    let groupKey = \"googleSearchPages\"\n\n    let request = this.http.get(url);\n    return this.cache.loadFromObservable(cacheKey, request, groupKey);\n}\n...\n```\n\nThen when pull to refresh is triggered, you can use the `clearGroup` method and pass in your group key.\n\n```ts\n...\npullToRefresh() {\n    this.cache.clearGroup(\"googleSearchPages\");\n}\n...\n```\n\n#### Set custom TTL for single request\n\nIf you want a custom TTL for a single request, you can pass it as the fourth parameter.\n\n```ts\nlet ttl = 60 * 60 * 24 * 7; // TTL in seconds for one week\nlet request = this.http.get(url);\n\nreturn this.cache.loadFromObservable(cacheKey, request, groupKey, ttl);\n```\n\n#### Set default TTL\n\n```ts\nthis.cache.setDefaultTTL(60 * 60); //set the default cache TTL for 1 hour\n```\n\n#### Delete expired entries\n\nIt's automatically done on every startup, but you can do it manually.\n\n```ts\nthis.cache.clearExpired();\n```\n\n#### Delete all entries\n\n**!Important!**\n\nMake sure that you have a `keyPrefix` set in the CacheModule config, otherwise this will clear everything in Ionic Storage.\n\n```ts\nthis.cache.clearAll();\n```\n\n#### Disable cache\n\nYou can disable cache without any issues, it will pass all of the original Observables through and all Promises will be rejected.\n\n```ts\nthis.cache.enableCache(false);\n```\n\n#### Disable offline invalidation\n\nYou can also disable invalidating cached items when the device is offline.\n\n```ts\nthis.cache.setOfflineInvalidate(false);\n```\n\n## Contributors ✨\n\n#### Maintainers:\n\n-   [Will Poulson](https://github.com/WillPoulson)\n-   [Daniel Suchy](https://github.com/Nodonisko)\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://danielsuchy.cz/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/5837757?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDaniel Suchý\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#ideas-Nodonisko\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=Nodonisko\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=Nodonisko\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/Nodonisko/ionic-cache/pulls?q=is%3Apr+reviewed-by%3ANodonisko\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://willpoulson.co.uk/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/12980659?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eWill Poulson\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=WillPoulson\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=WillPoulson\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/Nodonisko/ionic-cache/pulls?q=is%3Apr+reviewed-by%3AWillPoulson\" title=\"Reviewed Pull Requests\"\u003e👀\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://zyramedia.com/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/13794420?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eIbby Hadeed\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=ihadeed\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/darthdie\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/4060546?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBowser\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=darthdie\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/vojtatranta\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/4154045?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eVojtěch Tranta\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=vojtatranta\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003e\u003ca href=\"https://github.com/bpfrare\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/1761802?v=4?s=100\" width=\"100px;\" alt=\"\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eBruno Frare\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/Nodonisko/ionic-cache/commits?author=bpfrare\" title=\"Code\"\u003e💻\u003c/a\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnodonisko%2Fionic-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnodonisko%2Fionic-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnodonisko%2Fionic-cache/lists"}